/**
 * Extends Mobile est une bibliothèque d'extension basé sur JqueryMobile et une partie de l'implémentation prototype (version 1.7) pour la création de classe Objet.
 * Cette bibliothèque ajoute un certain nombre de fonction standard pour la bibliothèque graphique Window Mobile.
 * version 0.1
 * date 18/02/2011
 * author lenzotti romain
 **/
 
/**
 * == Language ==
 * Additions to JavaScript's "standard library" and extensions to
 * built-in JavaScript objects.
**/

/**
 *  == DOM ==
 *  Extensions to DOM elements, plus other utilities for DOM traversal
 *  and modification.
 *
 *  Prototype's DOM extensions represent a large portion of where you'll spend
 *  your time. Prototype adds many convenience methods to elements returned by
 *  the [[$]] function. For instance, you can write
 *
 *      $p('comments').addClassName('active').show();
 *
 *  to get the element with the ID of `comments`, add a class name to it, and
 *  show it (if it was previously hidden).
 *
 *  In other words, Prototype adds "instance" methods to DOM nodes. This is
 *  made possible by direct extension of the backing DOM objects (in browsers
 *  that support it) and by manual extension of individual nodes (in browsers
 *  that do not).
 *
**/
 
/** section: Language
 * Extends
 * Cette classe est le noyau de la bibliothèque Extends. Elle vérifie la précondition de chargement de la bibliothèque. 
 * Cette précondition et la version du prototype requis pour ce lancer (voir `Extends::REQUIRED_PROTOTYPE`).
 * Ces autres fonctions sont de s'occuper du chargement des outils externes à la bibliothèque (comme Window JS) et
 * le chargement du gestionnaire de langage Multilingue.
 **/
var Extends = {
/** 
 * Extends.Version -> String
 * Indique la version de la bibliothèque extends (read-only)
 **/
  	Version: 			'0.1',
/** 
 * Extends.URL -> String
 * Url de la page en cours d'éxécution
 **/
	URL: 				'',
/** 
 * Extends.PATH -> String
 * Lien du dossier de la bibliothèque extends (accessible après chargement de la bibliothèque)
 **/
	PATH:				'',
	callbacks:			{},
/**
 * Extends.plugins -> Array
 * liste des plugins qui seront inclut lors du lancement d'Extends
 **/
	plugins:			[
		'dom/node.js',
		'dom/event.js',
		'lang/date.js',
		'lang/string.js',
		'ui/tabcontrol.js'
	],
/**
 * Extends.fire(eventName) -> void
 * - eventName (String): Nom de l'événement à éxécuter.
 *
 * Execute un nom d'événement enregistré dans le gestion des événements d'Extends.
 **/
	fire: function(eventName){
		
		if(!Object.isUndefined(this.callbacks[eventName])){
			
			var properties = $A(arguments);
			var args = [];
	
			for(var i = 1; i < properties.length; i += 1){
				args.push(properties[i]);
			}
			
			for(var i = 0; i < this.callbacks[eventName].length; i+=1){
				try{
					if(Object.isFunction(this.callbacks[eventName][i])){
						this.callbacks[eventName][i].apply('', args);
					}
				}catch(er){}
			}
			
		}
	},
/**
 * Extends.load( ) -> undefined
 * Charge la bibliothèque Extends et les bibliothèques externes.
 **/
	load: function() {
		
		Extends.URL = ((""+window.location).split('#')[0]).split('?')[0];

		var file = window.location.pathname.split("/");
		Extends.URL = Extends.URL.replace(file[file.length - 1], '');
			
		$A(document.getElementsByTagName("script")).findAll(
			function(s) {
				return (s.src && s.src.match(/extends\.js(\?.*)?$/));
			}
		).each(
			function(s) {
				var path = s.src.replace(/extends\.js(\?.*)?$/,'');			
				var includes = s.src.match(/\?.*import=([a-z,]*)/);
				
				Extends.PATH = path;
				//chargement des bibliothèques statiques
				for(var i = 0; i < Extends.plugins.length; ++i){
					include(Extends.PATH + Extends.plugins[i]);	
				}
				
				//chargement des bibliothèques externe
				if(includes) includes[1].split(',').each(
				
					function(include) { 
						Extends.require(path+include+'.js');
					}
				);
	
				var lang = s.src.match(/\&.*lang=([a-z,]*)/);
				if(lang =='' || lang == null) MUI.setLang('fr');
				else MUI.setLang(lang[1]);
			});
		
		
	},
/**
 * Extends.ready(callback) -> void
 * - callback (Function): Fonction lié au nom de l'événement.
 *
 * Cette méthode enregistre un écouteur et sera appellé lorsque la biliothèque JQuery, Extends et le Dom seront complétement chargé.
 * 
 **/
 	ready: function(callback){
		this.observe('dom:loaded', callback);
	},
/**
 * Extends.observe(eventName, callback) -> void
 * - eventName (String): Nom de l'événement.
 * - callback (Function): Fonction lié au nom de l'événement.
 *
 * Enregistre une fonction lié à un nom d'événement dans le gestionnaire d'événement.
 * Cette fonction sera appellé lors du déclenchement de l'événement via `Extends.fire()`.
 * 
 **/
	observe: function(eventName, callback){
		if(!Object.isArray(this.callbacks[eventName])){
			this.callbacks[eventName] = [];	
		}
		this.callbacks[eventName].push(callback);
	},
/**
 * Extends.stopObserving(eventName, callback) -> undefined
 * - eventName (String): Nom de l'événement à stopper.
 * 
 * Stop un nom d'événement. Toutes les fonctions liées au nom ne seront plus appellés.
 *
 **/
	stopObserving: function(eventName, callback){
		if(Object.isUndefined(this.callbacks[eventName])){
			return;
		}
		var array = this.callbacks[eventName];
		this.callbacks[eventName] = new Array();
		
		for(var i = 0; i < array.length; i += 1){
			
			if(array[i] == callback) continue;
			this.callbacks[eventName].push(array[i]);
		}
	},
/** 
 * Extends.require(libraryName) -> undefined
 * - libraryName (String): Lien du script JS à inclure.
 * 
 * Inclut le fichier JS.
 * 
 **/
	require: function(libraryName) {
		// inserting via DOM fails in Safari 2.0, so brute force approach
		try{
			document.getElementsByName('head')[0].appendChild(new Node('script', {type:'text/javascript', src:libraryName}));	
		}catch(er){
			document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
		}
	},
/** 
 * Extends.include(libraryName) -> undefined
 * - libraryName (String): Lien du script JS à inclure.
 * 
 * Inclut le fichier JS.
 * 
 **/
	include: function(libraryName) {
		// inserting via DOM fails in Safari 2.0, so brute force approach
		try{
			document.getElementsByName('head')[0].appendChild(new Node('script', {type:'text/javascript', src:libraryName}));	
		}catch(er){
			document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>');
		}
	}
	
};
/** section: Language
 * include(libraryName) -> void
 * - libraryName (String): Lien du script JS à inclure.
 * 
 * Inclut le fichier JS.
 **/
function include(){
	var args = $A(arguments);
	
	if(args.length == 0) return;
	
	if(args.length == 1){
		Extends.include(args[0]);
	}else{
		for	(var i = 1; i < args.length; i+=1){
			
			Extends.include(args[0] + args[i] + '.js');
		}
	}
	return 
};
/** section: Language
 * MUI
 * Ce module met à disposition un outil simple de traduction de langue. Ce module ce base sur un fichier de traduction et
 * un tableau associatif de mots qui seront remplacé par leurs traductions équivalentes.
 **/
var MUI = {
/**
 * MUI.lang -> String
 * Indique la langue actuellement chargé par le traducteur.
 **/
	lang:'',
/**
 * MUI.month -> Object
 * Contient un tableau associatif des langues. Pour chaque langue on associe un tableau de mois qui serviront 
 * à la traduction.
 **/
	month:	{
/*
 * MUI.month.fr -> Array
 * Description des mois dans la langue française.
 **/
		fr:	['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
/*
 * MUI.month.eng -> Array
 * Description des mois dans la langue anglaise.
 **/
		eng:['January', 'February', 'Marsh', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
	},
/**
 * MUI.days -> Object
 * Contient un tableau associatif des langues. Pour chaque langue on associe un tableau de jour qui serviront 
 * à la traduction.
 **/
	days: 	{
/*
 * MUI.days.fr -> Array
 * Description des jours dans la langue française.
 **/
		fr:	['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
/*
 * MUI.days.eng -> Array
 * Description des jours dans la langue anglaise.
 **/
		eng:['Sunday','Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
	},
/**
 * MUI.text -> Object
 * Contient un tableau associatif des langues. L'objet text contient une liste de mot écrit dans l'application
 * cible et associe leur traduction.
 **/
	text:	{fr:{}, eng:{}},
/**
 * MUI.addWord(key, word, lang) -> void
 * - key (String): Mot clef de l'application cible.
 * - word (String): Traduction du mot clef dans la langue cible.
 * - lang (String): Langue associée à la traduction.
 *
 * Cette méthode ajoute une traduction d'un mot au dictionnaire de mot.
 **/
	addWord:function(key, wordtrad, lang){
		if(Object.isUndefined(lang)) lang = this.lang;
		this.text[lang][key.toLowerCase()] = wordtrad;
	},
/**
 * MUI.addWords(obj, lang) -> void
 * - obj (Object): Dictionnaire de mot à ajouter.
 * - lang (String): Langue associée à la traduction.
 *
 * Cette méthode ajoute un dictionnaire de mot au dictionnaire courrant.
 *
 * ##### Description du paramètre obj
 *
 * Le paramètre obj doit être décrit de la façon suivante :
 *	
 *     var obj = {
 *         'mot cible': 'mot traduit',
 *         'mot cible2': 'mot traduit 2',
 *         //etc...
 *     }
 *
 *
 **/
	addWords: function(obj, lang){
		for(var key in obj){
			this.addWord(key, obj[key], lang);	
		}
	},
/**
 * MUI.translate(word) -> String
 * - word (String): Mot à traduire.
 *
 * Traduit le mot à partir de langue par défaut et de son dictionnaire associé.
 * 
 * ##### Exemple
 *
 * Voici un exemple simple d'utilisation :
 * 
 *     MUI.addWord('bonjour le monde', 'hello world', 'eng');
 *     
 *     MUI.lang = 'eng';
 *     alert(MUI.translate('bonjour le monde')); //hello world
 *     //autre fonction plus rapide à écrire
 *     alert($MUI('bonjour le monde')); //hello world
 *
 **/
	translate: function(text){
		if(this.lang == '') return text;
		var value = this.text[this.lang][text];

		if(value =='' || Object.isUndefined(value))	{
			value = this.text[this.lang][text.toLowerCase()];
			if(value =='' || Object.isUndefined(value)) return text;
		}
		return value;
	},
/**
 * MUI.getMonth(it) -> String
 * - it (Number): Numéro du mois.
 * 
 * Cette méthode prend en paramètre le numéro du mois entre 0 et 11, et retourne la traduction
 * du mois en fonction de la langue. Si la traduction du mois n'existe pas dans la langue
 * choisie, la méthode retournera la traduction de langue par défaut (Anglais).
 **/
	getMonth: function(i){
		var value ='';
		try{
			value = this.month[this.lang][i];
		}
		catch(er){
			value = this.month['eng'][i];
		}
		return value;
	},
	//ignore
	getMonths: function(i){
		return this.month[this.lang].clone();
	},
/**
 * MUI.getDay(it) -> String
 * - it (Number): Numéro du jour.
 * 
 * Cette méthode prend en paramètre le numéro du jours entre 0 et 6, et retourne sa traduction
 * en fonction de la langue. Si la traduction du jour n'existe pas dans la langue
 * choisie, la méthode retournera la traduction de langue par défaut (Anglais).
 **/
	getDay: function(i){

		var value ='';
		try{
			value = this.days[this.lang][i];
		}
		catch(er){
			try{
				value = this.days['eng'][i];
			}catch(er){
				return i;	
			}
		}
		return value;
	},
/**
 * MUI.setLang(lang) -> void
 * - lang (lang): Langue du dictionnaire.
 *
 * Cette méthode change la langue par défaut du dictionnaire de mot et charge le
 * fichier de traduction associé à la langue dans le dossier de référence
 * (/MUI/LANG_lang.js). 
 *
 * Si lang est fr alors le fichier chargé sera FR_fr.js. En théorie le fichier
 * multilingue doit contenir l'ensemble des mots de traduction de l'application
 * cible.
 *
 **/
	setLang: function(lang){
		this.lang = lang.toLowerCase();
		Extends.require(Extends.URL + 'MUI/'+this.lang.toUpperCase()+'_'+this.lang.toLowerCase()+'.js');
	}
};
/** alias of: MUI.translate, section: Language
 * $MUI(text) -> String
 * 
 * Cette fonction permet la traduction de mot vers une langue cible.
 * Cette langue cible est définit par la classe [[MUI]].
 *
 * ##### Exemple
 *
 * Voici un exemple simple d'utilisation :
 * 
 *     MUI.addWord('bonjour le monde', 'hello world', 'eng');
 *     MUI.lang = 'eng';
 *     alert(MUI.translate('bonjour le monde')); //hello world
 *     //autre fonction plus rapide à écrire
 *     alert($MUI('bonjour le monde')); //hello world
 **/
function $MUI(text){
	return MUI.translate(text);
}
/**
 * Prototype
 *
 *  The [[Prototype]] namespace provides fundamental information about the
 *  Prototype library you're using, as well as a central repository for default
 *  iterators or functions.
 *
 *  We say "namespace," because the [[Prototype]] object is not intended for
 *  instantiation, nor for mixing in other objects. It's really just... a
 *  namespace.
 *
 *  ##### Your version of Prototype
 *
 *  Your scripts can check against a particular version of Prototype by
 *  examining [[Prototype.Version]], which is a version [[String]] (e.g.
 *  "<%= PROTOTYPE_VERSION %>"). The famous
 *  [script.aculo.us](http://script.aculo.us) library does this at load time to
 *  ensure it's being used with a reasonably recent version of Prototype, for
 *  instance.
 *
 *  ##### Browser features
 *
 *  Prototype also provides a (nascent) repository of
 *  [[Prototype.BrowserFeatures browser feature information]], which it then
 *  uses here and there in its source code. The idea is, first, to make
 *  Prototype's source code more readable; and second, to centralize whatever
 *  scripting trickery might be necessary to detect the browser feature, in
 *  order to ease maintenance.
 *
 *  ##### Default iterators and functions
 *
 *  Numerous methods in Prototype objects (most notably the [[Enumerable]]
 *  module) let the user pass in a custom iterator, but make it optional by
 *  defaulting to an "identity function" (an iterator that just returns its
 *  argument, untouched). This is the [[Prototype.K]] function, which you'll
 *  see referred to in many places.
 *
 *  Many methods also take it easy by protecting themselves against missing
 *  methods here and there, reverting to empty functions when a supposedly
 *  available method is missing. Such a function simply ignores its potential
 *  arguments, and does nothing whatsoever (which is, oddly enough,
 *  blazing fast). The quintessential empty function sits, unsurprisingly,
 *  at [[Prototype.emptyFunction]] (note the lowercase first letter).
**/
var Prototype = {

  /**
   *  Prototype.Version -> String
   *
   *  The version of the Prototype library you are using (e.g.
   *  "<%= PROTOTYPE_VERSION %>").
  **/
  Version: '1.7',

  /**
   *  Prototype.Browser
   *
   *  A collection of [[Boolean]] values indicating the browser which is
   *  currently in use. Available properties are `IE`, `Opera`, `WebKit`,
   *  `MobileSafari` and `Gecko`.
   *
   *  Example
   *
   *      Prototype.Browser.WebKit;
   *      //-> true, when executed in any WebKit-based browser.
  **/
  Browser: (function(){
    var ua = navigator.userAgent;
    // Opera (at least) 8.x+ has "Opera" as a [[Class]] of `window.opera`
    // This is a safer inference than plain boolean type conversion of `window.opera`
    var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
    return {
      IE:             !!window.attachEvent && !isOpera,
      Opera:          isOpera,
      WebKit:         ua.indexOf('AppleWebKit/') > -1,
      Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
      MobileSafari:   /Apple.*Mobile/.test(ua)
    }
  })(),

  /**
   *  Prototype.BrowserFeatures
   *
   *  A collection of [[Boolean]] values indicating the presence of specific
   *  browser features.
  **/
  BrowserFeatures: {
    /**
     *  Prototype.BrowserFeatures.XPath -> Boolean
     *
     *  Used internally to detect if the browser supports
     *  [DOM Level 3 XPath](http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html).
    **/
    XPath: !!document.evaluate,

    /**
     *  Prototype.BrowserFeatures.SelectorsAPI -> Boolean
     *
     *  Used internally to detect if the browser supports the
     *  [NodeSelector API](http://www.w3.org/TR/selectors-api/#nodeselector).
    **/
    SelectorsAPI: !!document.querySelector,

    /**
     *  Prototype.BrowserFeatures.ElementExtensions -> Boolean
     *
     *  Used internally to detect if the browser supports extending html element
     *  prototypes.
    **/
    ElementExtensions: (function() {
      var constructor = window.Element || window.HTMLElement;
      return !!(constructor && constructor.prototype);
    })(),
    SpecificElementExtensions: (function() {
      // First, try the named class
      if (typeof window.HTMLDivElement !== 'undefined')
        return true;

      var div = document.createElement('div'),
          form = document.createElement('form'),
          isSupported = false;

      if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
        isSupported = true;
      }

      div = form = null;

      return isSupported;
    })()
  },

  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,

  /**
   *  Prototype.emptyFunction([argument...]) -> undefined
   *  - argument (Object): Optional arguments
   *
   *  The [[Prototype.emptyFunction]] does nothing... and returns nothing!
   *
   *  It is used thoughout the framework to provide a fallback function in order
   *  to cut down on conditionals. Typically you'll find it as a default value
   *  for optional callback functions.
  **/
  emptyFunction: function() { },

  /**
   *  Prototype.K(argument) -> argument
   *  - argument (Object): Optional argument...
   *
   *  [[Prototype.K]] is Prototype's very own
   *  [identity function](http://en.wikipedia.org/wiki/Identity_function), i.e.
   *  it returns its `argument` untouched.
   *
   *  This is used throughout the framework, most notably in the [[Enumerable]]
   *  module as a default value for iterators.
   *
   *  ##### Examples
   *
   *      Prototype.K('hello world!');
   *      // -> 'hello world!'
   *
   *      Prototype.K(200);
   *      // -> 200
   *
   *      Prototype.K(Prototype.K);
   *      // -> Prototype.K
  **/
  K: function(x) { return x }
};

if (Prototype.Browser.MobileSafari)
  Prototype.BrowserFeatures.SpecificElementExtensions = false;
/* Based on Alex Arnell's inheritance implementation. */

/** section: Language
 * class Class
 *
 *  Manages Prototype's class-based OOP system.
 *
 *  Refer to Prototype's web site for a [tutorial on classes and
 *  inheritance](http://prototypejs.org/learn/class-inheritance).
**/
var Class = (function() {
  
  // Some versions of JScript fail to enumerate over properties, names of which 
  // correspond to non-enumerable properties in the prototype chain
  var IS_DONTENUM_BUGGY = (function(){
    for (var p in { toString: 1 }) {
      // check actual property name, so that it works with augmented Object.prototype
      if (p === 'toString') return false;
    }
    return true;
  })();
  
  /**
   *  Class.create([superclass][, methods...]) -> Class
   *    - superclass (Class): The optional superclass to inherit methods from.
   *    - methods (Object): An object whose properties will be "mixed-in" to the
   *        new class. Any number of mixins can be added; later mixins take
   *        precedence.
   *
   *  [[Class.create]] creates a class and returns a constructor function for
   *  instances of the class. Calling the constructor function (typically as
   *  part of a `new` statement) will invoke the class's `initialize` method.
   *
   *  [[Class.create]] accepts two kinds of arguments. If the first argument is
   *  a [[Class]], it's used as the new class's superclass, and all its methods
   *  are inherited. Otherwise, any arguments passed are treated as objects,
   *  and their methods are copied over ("mixed in") as instance methods of the
   *  new class. In cases of method name overlap, later arguments take
   *  precedence over earlier arguments.
   *
   *  If a subclass overrides an instance method declared in a superclass, the
   *  subclass's method can still access the original method. To do so, declare
   *  the subclass's method as normal, but insert `$super` as the first
   *  argument. This makes `$super` available as a method for use within the
   *  function.
   *
   *  To extend a class after it has been defined, use [[Class#addMethods]].
   *
   *  For details, see the
   *  [inheritance tutorial](http://prototypejs.org/learn/class-inheritance)
   *  on the Prototype website.
  **/
  function subclass() {};
  function create() {
	var parent = null, properties = $A(arguments);
	if (Object.isFunction(properties[0]))
		parent = properties.shift();
		
		function klass() {
		this.initialize.apply(this, arguments);
	}
	
	Object.extend(klass, Class.Methods);
	klass.superclass = parent;
	klass.subclasses = [];
	
	if (parent) {
		subclass.prototype = parent.prototype;
		klass.prototype = new subclass;
		parent.subclasses.push(klass);
	}
	
	for (var i = 0, length = properties.length; i < length; i++)
		klass.addMethods(properties[i]);
	
	if (!klass.prototype.initialize)
		klass.prototype.initialize = Prototype.emptyFunction;
	
	klass.prototype.constructor = klass;
	
	return klass;
  }

  /**
   *  Class#addMethods(methods) -> Class
   *    - methods (Object): The methods to add to the class.
   *
   *  Adds methods to an existing class.
   *
   *  [[Class#addMethods]] is a method available on classes that have been
   *  defined with [[Class.create]]. It can be used to add new instance methods
   *  to that class, or overwrite existing methods, after the class has been
   *  defined.
   *
   *  New methods propagate down the inheritance chain. If the class has
   *  subclasses, those subclasses will receive the new methods &mdash; even in
   *  the context of `$super` calls. The new methods also propagate to instances
   *  of the class and of all its subclasses, even those that have already been
   *  instantiated.
   *
   *  ##### Examples
   *
   *      var Animal = Class.create({
   *        initialize: function(name, sound) {
   *          this.name  = name;
   *          this.sound = sound;
   *        },
   *
   *        speak: function() {
   *          alert(this.name + " says: " + this.sound + "!");
   *        }
   *      });
   *
   *      // subclassing Animal
   *      var Snake = Class.create(Animal, {
   *        initialize: function($super, name) {
   *          $super(name, 'hissssssssss');
   *        }
   *      });
   *
   *      var ringneck = new Snake("Ringneck");
   *      ringneck.speak();
   *
   *      //-> alerts "Ringneck says: hissssssss!"
   *
   *      // adding Snake#speak (with a supercall)
   *      Snake.addMethods({
   *        speak: function($super) {
   *          $super();
   *          alert("You should probably run. He looks really mad.");
   *        }
   *      });
   *
   *      ringneck.speak();
   *      //-> alerts "Ringneck says: hissssssss!"
   *      //-> alerts "You should probably run. He looks really mad."
   *
   *      // redefining Animal#speak
   *      Animal.addMethods({
   *        speak: function() {
   *          alert(this.name + 'snarls: ' + this.sound + '!');
   *        }
   *      });
   *
   *      ringneck.speak();
   *      //-> alerts "Ringneck snarls: hissssssss!"
   *      //-> alerts "You should probably run. He looks really mad."
  **/
  function addMethods(source) {
    var ancestor   = this.superclass && this.superclass.prototype,
        properties = Object.keys(source);

    // IE6 doesn't enumerate `toString` and `valueOf` (among other built-in `Object.prototype`) properties,
    // Force copy if they're not Object.prototype ones.
    // Do not copy other Object.prototype.* for performance reasons
    if (IS_DONTENUM_BUGGY) {
      if (source.toString != Object.prototype.toString)
        properties.push("toString");
      if (source.valueOf != Object.prototype.valueOf)
        properties.push("valueOf");
    }

    for (var i = 0, length = properties.length; i < length; i++) {
      var property = properties[i], value = source[property];
      if (ancestor && Object.isFunction(value) &&
          value.argumentNames()[0] == "$super") {
        var method = value;
        value = (function(m) {
          return function() { return ancestor[m].apply(this, arguments); };
        })(property).wrap(method);

        value.valueOf = method.valueOf.bind(method);
        value.toString = method.toString.bind(method);
      }
      this.prototype[property] = value;
    }

    return this;
  }
/**
 * Class.createSprite(baliseName) -> Element Class
 * - baliseName (String): Nom de la balise. La classe héritera des propriétés de la balise demandée.
 *
 * Créer une classe hérité de la classe Element. Cette dernière pourra être ajouté à un `element` du DOM JavaScript.
 * 
 * ##### Exemple
 * 
 * Cet exemple montre comment utiliser la méthode [[Class.createSprite]].
 *
 *      var MaClasse = Class.createSprite('div');
 *            MaClasse.prototype = {
 *                  initialize: function(){
 *                  this.innerHTML = 'ma classe element';
 *            }
 *      };
 *      document.stage.body.appendChild(new MaClasse());
 * 
 * <p class="note">Tout comme les classes créer par `Class.create()`, vous pouvez écrire vos attributs classe dans le 
 * corps de MaClasse.prototype.</p>
 *
 **/
	function createSprite() {
		var name = null, parent = null, properties = $A(arguments);

		if(Object.isString(properties[0])) {
			name = 			properties[0];
			properties = 	properties.shift();
		}
		if(Object.isFunction(properties[0])) parent = properties.shift();

		/**
		 * @ignore
		 */
		function klass() {
			
			if(name != null){
				var element  = new Node(name);
	
				Object.extend(element, this);
	
				element.initialize.apply(element, arguments);
							
				return element;
			}
			return this.initialize.apply(this, arguments);
		}
		
		Object.extend(klass, Class.Methods);
		klass.superclass = parent;
		klass.subclasses = [];
		
		if (parent) {
			/**
			 * @ignore
			 */
			var subclass = function() { };
			subclass.prototype = parent.prototype;
			klass.prototype = new subclass;
			parent.subclasses.push(klass);
		}
		
		for (var i = 0; i < properties.length; i++){
			try{
				//klass.addMethods(properties[i]);
			}catch(er){}
		}
		
		if(!klass.prototype.initialize)	klass.prototype.initialize = Prototype.emptyFunction;
		
		klass.prototype.constructor = klass;
		
		return klass;
	};
	
	return {
		create: create,
		createSprite: createSprite,
		Methods: {
			addMethods: addMethods
		}
	};
})();
/** section: Language
 * class Object
 *
 *  Extensions to the built-in [[Object]] object.
 *
 *  Because it is dangerous and invasive to augment `Object.prototype` (i.e.,
 *  add instance methods to objects), all these methods are static methods that
 *  take an [[Object]] as their first parameter.
 *
 *  [[Object]] is used by Prototype as a namespace; that is, it just keeps a few 
 *  new methods together, which are intended for namespaced access (i.e. starting
 *  with "`Object.`").
 *  
 *  For the regular developer (who simply uses Prototype without tweaking it), the
 *  most commonly used methods are probably [[Object.inspect]] and, to a lesser degree, 
 *  [[Object.clone]].
 *  
 *  Advanced users, who wish to create their own objects like Prototype does, or
 *  explore objects as if they were hashes, will turn to [[Object.extend]], 
 *  [[Object.keys]], and [[Object.values]].
**/
(function() {

  var _toString = Object.prototype.toString,
      NULL_TYPE = 'Null',
      UNDEFINED_TYPE = 'Undefined',
      BOOLEAN_TYPE = 'Boolean',
      NUMBER_TYPE = 'Number',
      STRING_TYPE = 'String',
      OBJECT_TYPE = 'Object',
      FUNCTION_CLASS = '[object Function]',
      BOOLEAN_CLASS = '[object Boolean]',
      NUMBER_CLASS = '[object Number]',
      STRING_CLASS = '[object String]',
      ARRAY_CLASS = '[object Array]',
      DATE_CLASS = '[object Date]',
      NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON &&
        typeof JSON.stringify === 'function' &&
        JSON.stringify(0) === '0' &&
        typeof JSON.stringify(Prototype.K) === 'undefined';
        
  function Type(o) {
    switch(o) {
      case null: return NULL_TYPE;
      case (void 0): return UNDEFINED_TYPE;
    }
    var type = typeof o;
    switch(type) {
      case 'boolean': return BOOLEAN_TYPE;
      case 'number':  return NUMBER_TYPE;
      case 'string':  return STRING_TYPE;
    }
    return OBJECT_TYPE;
  }

  /**
   *  Object.extend(destination, source) -> Object
   *  - destination (Object): The object to receive the new properties.
   *  - source (Object): The object whose properties will be duplicated.
   *
   *  Copies all properties from the source to the destination object. Used by Prototype
   *  to simulate inheritance (rather statically) by copying to prototypes.
   *  
   *  Documentation should soon become available that describes how Prototype implements
   *  OOP, where you will find further details on how Prototype uses [[Object.extend]] and
   *  [[Class.create]] (something that may well change in version 2.0). It will be linked
   *  from here.
   *  
   *  Do not mistake this method with its quasi-namesake [[Element.extend]],
   *  which implements Prototype's (much more complex) DOM extension mechanism.
  **/
  function extend(destination, source) {
    for (var property in source)
      destination[property] = source[property];
    return destination;
  }

  /**
   *  Object.inspect(obj) -> String
   *  - object (Object): The item to be inspected.
   *  
   *  Returns the debug-oriented string representation of the object.
   *  
   *  * `undefined` and `null` are represented as such.
   *  * Other types are looked up for a `inspect` method: if there is one, it is used, otherwise,
   *  it reverts to the `toString` method.
   *  
   *  Prototype provides `inspect` methods for many types, both built-in and library-defined,
   *  such as in [[String#inspect]], [[Array#inspect]], [[Enumerable#inspect]] and [[Hash#inspect]],
   *  which attempt to provide most-useful string representations (from a developer's standpoint)
   *  for their respective types.
   *  
   *  ##### Examples
   *  
   *      Object.inspect();
   *      // -> 'undefined'
   *      
   *      Object.inspect(null);
   *      // -> 'null'
   *      
   *      Object.inspect(false);
   *      // -> 'false'
   *      
   *      Object.inspect([1, 2, 3]);
   *      // -> '[1, 2, 3]'
   *      
   *      Object.inspect('hello');
   *      // -> "'hello'"
  **/
  function inspect(object) {
    try {
      if (isUndefined(object)) return 'undefined';
      if (object === null) return 'null';
      return object.inspect ? object.inspect() : String(object);
    } catch (e) {
      if (e instanceof RangeError) return '...';
      throw e;
    }
  }

  /**
   *  Object.toJSON(object) -> String
   *  - object (Object): The object to be serialized.
   *
   *  Returns a JSON string.
   *
   *  `undefined` and `function` types have no JSON representation. `boolean`
   *  and `null` are coerced to strings.
   *
   *  For other types, [[Object.toJSON]] looks for a `toJSON` method on `object`.
   *  If there is one, it is used; otherwise the object is treated like a
   *  generic [[Object]].
   *  
   *  For more information on Prototype's JSON encoder, hop to our
   *  [tutorial](http://prototypejs.org/learn/json).
   *  
   *  ##### Example
   *  
   *      var data = {name: 'Violet', occupation: 'character', age: 25, pets: ['frog', 'rabbit']};
   *      Object.toJSON(data);
   *      //-> '{"name": "Violet", "occupation": "character", "age": 25, "pets": ["frog","rabbit"]}'
  **/
  function toJSON(value) {
    return Str('', { '': value }, []);
  }

  function Str(key, holder, stack) {
    var value = holder[key],
        type = typeof value;

    if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') {
      value = value.toJSON(key);
    }

    var _class = _toString.call(value);

    switch (_class) {
      case NUMBER_CLASS:
      case BOOLEAN_CLASS:
      case STRING_CLASS:
        value = value.valueOf();
    }

    switch (value) {
      case null: return 'null';
      case true: return 'true';
      case false: return 'false';
    }

    type = typeof value;
    switch (type) {
      case 'string':
        return value.inspect(true);
      case 'number':
        return isFinite(value) ? String(value) : 'null';
      case 'object':

        for (var i = 0, length = stack.length; i < length; i++) {
          if (stack[i] === value) { throw new TypeError(); }
        }
        stack.push(value);

        var partial = [];
        if (_class === ARRAY_CLASS) {
          for (var i = 0, length = value.length; i < length; i++) {
            var str = Str(i, value, stack);
            partial.push(typeof str === 'undefined' ? 'null' : str);
          }
          partial = '[' + partial.join(',') + ']';
        } else {
          var keys = Object.keys(value);
          for (var i = 0, length = keys.length; i < length; i++) {
            var key = keys[i], str = Str(key, value, stack);
            if (typeof str !== "undefined") {
               partial.push(key.inspect(true)+ ':' + str);
             }
          }
          partial = '{' + partial.join(',') + '}';
        }
        stack.pop();
        return partial;
    }
  }

  function stringify(object) {
    return JSON.stringify(object);
  }

  /**
   *  Object.toQueryString(object) -> String
   *  - object (Object): The object whose property/value pairs will be converted.
   *
   *  Turns an object into its URL-encoded query string representation.
   *
   *  This is a form of serialization, and is mostly useful to provide complex
   *  parameter sets for stuff such as objects in the [[Ajax]] namespace (e.g.
   *  [[Ajax.Request]]).
   *
   *  Undefined-value pairs will be serialized as if empty-valued. Array-valued
   *  pairs will get serialized with one name/value pair per array element. All
   *  values get URI-encoded using JavaScript's native `encodeURIComponent`
   *  function.
   *
   *  The order of pairs in the serialized form is not guaranteed (and mostly
   *  irrelevant anyway) &mdash; except for array-based parts, which are serialized
   *  in array order.
   *  
   *  ##### Examples
   *  
   *      Object.toQueryString({ action: 'ship', order_id: 123, fees: ['f1', 'f2'], 'label': 'a demo' })
   *      // -> 'action=ship&order_id=123&fees=f1&fees=f2&label=a%20demo'
  **/
  function toQueryString(object) {
    return $H(object).toQueryString();
  }

  /**
   *  Object.toHTML(object) -> String
   *  - object (Object): The object to convert to HTML.
   *
   *  Converts the object to its HTML representation.
   *
   *  Returns the return value of `object`'s `toHTML` method if it exists; else
   *  runs `object` through [[String.interpret]].
   *  
   *  ##### Examples
   *  
   *      var Bookmark = Class.create({
   *        initialize: function(name, url) {
   *          this.name = name;
   *          this.url = url;
   *        },
   *        
   *        toHTML: function() {
   *          return '<a href="#{url}">#{name}</a>'.interpolate(this);
   *        }
   *      });
   *      
   *      var api = new Bookmark('Prototype API', 'http://prototypejs.org/api');
   *      
   *      Object.toHTML(api);
   *      //-> '<a href="http://prototypejs.org/api">Prototype API</a>'
   *      
   *      Object.toHTML("Hello world!");
   *      //-> "Hello world!"
   *      
   *      Object.toHTML();
   *      //-> ""
   *      
   *      Object.toHTML(null);
   *      //-> ""
   *      
   *      Object.toHTML(undefined);
   *      //-> ""
   *      
   *      Object.toHTML(true);
   *      //-> "true"
   *      
   *      Object.toHTML(false);
   *      //-> "false"
   *      
   *      Object.toHTML(123);
   *      //-> "123"
  **/
  function toHTML(object) {
    return object && object.toHTML ? object.toHTML() : String.interpret(object);
  }

  /**
   *  Object.keys(object) -> Array
   *  - object (Object): The object to pull keys from.
   *
   *  Returns an array of the object's property names.
   *
   *  Note that the order of the resulting array is browser-dependent &mdash; it
   *  relies on the `for...in` loop, for which the ECMAScript spec does not
   *  prescribe an enumeration order. Sort the resulting array if you wish to
   *  normalize the order of the object keys.
   *
   *  ##### Examples
   *  
   *      Object.keys();
   *      // -> []
   *      
   *      Object.keys({ name: 'Prototype', version: '1.6.1' }).sort();
   *      // -> ['name', 'version']
  **/
  function keys(object) {
    if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
    var results = [];
    for (var property in object) {
      if (object.hasOwnProperty(property)) {
        results.push(property);
      }
    }
    return results;
  }

  /**
   *  Object.values(object) -> Array
   *  - object (Object): The object to pull values from.
   *
   *  Returns an array of the object's property values.
   *
   *  Note that the order of the resulting array is browser-dependent &mdash; it
   *  relies on the `for...in` loop, for which the ECMAScript spec does not
   *  prescribe an enumeration order.
   *
   *  Also, remember that while property _names_ are unique, property _values_
   *  have no such constraint.
   *
   *  ##### Examples
   *  
   *      Object.values();
   *      // -> []
   *      
   *      Object.values({ name: 'Prototype', version: '1.6.1' }).sort();
   *      // -> ['1.6.1', 'Prototype']
  **/
  function values(object) {
    var results = [];
    for (var property in object)
      results.push(object[property]);
    return results;
  }

  /**
   *  Object.clone(object) -> Object
   *  - object (Object): The object to clone.
   *
   *  Creates and returns a shallow duplicate of the passed object by copying
   *  all of the original's key/value pairs onto an empty object.
   *
   *  Do note that this is a _shallow_ copy, not a _deep_ copy. Nested objects
   *  will retain their references.
   *
   *  ##### Examples
   *
   *      var original = {name: 'primaryColors', values: ['red', 'green', 'blue']};
   *      var copy = Object.clone(original);
   *
   *      original.name;
   *      // -> "primaryColors"
   *      original.values[0];
   *      // -> "red"
   *      copy.name;
   *      // -> "primaryColors"
   *      
   *      copy.name = "secondaryColors";
   *      original.name;
   *      // -> "primaryColors"
   *      copy.name;
   *      // -> "secondaryColors"
   *      
   *      copy.values[0] = 'magenta';
   *      copy.values[1] = 'cyan';
   *      copy.values[2] = 'yellow';
   *      original.values[0];
   *      // -> "magenta" (it's a shallow copy, so they share the array)
  **/
  function clone(object) {
    return extend({ }, object);
  }

  /**
   *  Object.isElement(object) -> Boolean
   *  - object (Object): The object to test.
   *
   *  Returns `true` if `object` is a DOM node of type 1; `false` otherwise.
   *  
   *  ##### Examples
   *  
   *      Object.isElement(new Element('div'));
   *      //-> true
   *      
   *      Object.isElement(document.createElement('div'));
   *      //-> true
   *      
   *      Object.isElement($('id_of_an_exiting_element'));
   *      //-> true
   *      
   *      Object.isElement(document.createTextNode('foo'));
   *      //-> false
  **/
  function isElement(object) {
    return !!(object && object.nodeType == 1);
  }

  /**
   *  Object.isArray(object) -> Boolean
   *  - object (Object): The object to test.
   *
   *  Returns `true` if `object` is an [[Array]]; `false` otherwise.
   *  
   *  ##### Examples
   *  
   *      Object.isArray([]);
   *      //-> true
   *      
   *      Object.isArray($w());
   *      //-> true
   *      
   *      Object.isArray({ });
   *      //-> false
  **/
  function isArray(object) {
    return _toString.call(object) === ARRAY_CLASS;
  }
  
  var hasNativeIsArray = (typeof Array.isArray == 'function') 
    && Array.isArray([]) && !Array.isArray({});
  
  if (hasNativeIsArray) {
    isArray = Array.isArray;
  }

  /**
   *  Object.isHash(object) -> Boolean
   *  - object (Object): The object to test.
   *
   *  Returns `true` if `object` is an instance of the [[Hash]] class; `false`
   *  otherwise.
   *  
   *  ##### Examples
   *  
   *      Object.isHash(new Hash({ }));
   *      //-> true
   *      
   *      Object.isHash($H({ }));
   *      //-> true
   *      
   *      Object.isHash({ });
   *      //-> false
  **/
  function isHash(object) {
    return object instanceof Hash;
  }

  /**
   *  Object.isFunction(object) -> Boolean
   *  - object (Object): The object to test.
   *
   *  Returns `true` if `object` is of type [[Function]]; `false` otherwise.
   *  
   *  ##### Examples
   *  
   *      Object.isFunction($);
   *      //-> true
   *      
   *      Object.isFunction(123);
   *      //-> false
  **/
  function isFunction(object) {
    return _toString.call(object) === FUNCTION_CLASS;
  }

  /**
   *  Object.isString(object) -> Boolean
   *  - object (Object): The object to test.
   *
   *  Returns `true` if `object` is of type [[String]]; `false` otherwise.
   *  
   *  ##### Examples
   *  
   *      Object.isString("foo");
   *      //-> true
   *      
   *      Object.isString("");
   *      //-> true
   *      
   *      Object.isString(123);
   *      //-> false
  **/
  function isString(object) {
    return _toString.call(object) === STRING_CLASS;
  }

  /**
   *  Object.isNumber(object) -> Boolean
   *  - object (Object): The object to test.
   *
   *  Returns `true` if `object` is of type [[Number]]; `false` otherwise.
   *  
   *  ##### Examples
   *  
   *      Object.isNumber(0);
   *      //-> true
   *      
   *      Object.isNumber(1.2);
   *      //-> true
   *      
   *      Object.isNumber("foo");
   *      //-> false
  **/
  function isNumber(object) {
    return _toString.call(object) === NUMBER_CLASS;
  }
  
  /**
   *  Object.isDate(object) -> Boolean
   *  - object (Object): The object to test.
   *  
   *  Returns `true` if `object` is of type [[Date]]; `false` otherwise.
   *  
   *  ##### Examples
   *  
   *      Object.isDate(new Date);
   *      //-> true
   *  
   *      Object.isDate("Dec 25, 1995");
   *      //-> false
   *  
   *      Object.isDate(new Date("Dec 25, 1995"));
   *      //-> true
  **/
  function isDate(object) {
    return _toString.call(object) === DATE_CLASS;
  }

  /**
   *  Object.isUndefined(object) -> Boolean
   *  - object (Object): The object to test.
   *
   *  Returns `true` if `object` is of type `undefined`; `false` otherwise.
   *  
   *  ##### Examples
   *  
   *      Object.isUndefined();
   *      //-> true
   *      
   *      Object.isUndefined(undefined);
   *      //-> true
   *      
   *      Object.isUndefined(null);
   *      //-> false
   *      
   *      Object.isUndefined(0);
   *      //-> false
   *      
   *      Object.isUndefined("");
   *      //-> false
  **/
  function isUndefined(object) {
    return typeof object === "undefined";
  }

  extend(Object, {
    extend:        extend,
    inspect:       inspect,
    toJSON:        NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON,
    toQueryString: toQueryString,
    toHTML:        toHTML,
    keys:          Object.keys || keys,
    values:        values,
    clone:         clone,
    isElement:     isElement,
    isArray:       isArray,
    isHash:        isHash,
    isFunction:    isFunction,
    isString:      isString,
    isNumber:      isNumber,
    isDate:        isDate,
    isUndefined:   isUndefined
  });
})();
/** section: Language
 * class Function
 *
 *  Extensions to the built-in `Function` object.
**/
Object.extend(Function.prototype, (function() {
  var slice = Array.prototype.slice;

  function update(array, args) {
    var arrayLength = array.length, length = args.length;
    while (length--) array[arrayLength + length] = args[length];
    return array;
  }

  function merge(array, args) {
    array = slice.call(array, 0);
    return update(array, args);
  }

  /**
   *  Function#argumentNames() -> Array
   *
   *  Reads the argument names as stated in the function definition and returns
   *  the values as an array of strings (or an empty array if the function is
   *  defined without parameters).
   *
   *  ##### Examples
   *
   *      function fn(foo, bar) {
   *        return foo + bar;
   *      }
   *      fn.argumentNames();
   *      //-> ['foo', 'bar']
   *
   *      Prototype.emptyFunction.argumentNames();
   *      //-> []
  **/
  function argumentNames() {
    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
      .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
      .replace(/\s+/g, '').split(',');
    return names.length == 1 && !names[0] ? [] : names;
  }

  /** related to: Function#bindAsEventListener
   *  Function#bind(context[, args...]) -> Function
   *  - context (Object): The object to bind to.
   *  - args (?): Optional additional arguments to curry for the function.
   *
   *  Binds this function to the given `context` by wrapping it in another
   *  function and returning the wrapper. Whenever the resulting "bound"
   *  function is called, it will call the original ensuring that `this` is set
   *  to `context`. Also optionally curries arguments for the function.
   *
   *  ##### Examples
   *
   *  A typical use of [[Function#bind]] is to ensure that a callback (event
   *  handler, etc.) that is an object method gets called with the correct
   *  object as its context (`this` value):
   *
   *      var AlertOnClick = Class.create({
   *        initialize: function(msg) {
   *          this.msg = msg;
   *        },
   *        handleClick: function(event) {
   *          event.stop();
   *          alert(this.msg);
   *        }
   *      });
   *      var myalert = new AlertOnClick("Clicked!");
   *      $p('foo').observe('click', myalert.handleClick); // <= WRONG
   *      // -> If 'foo' is clicked, the alert will be blank; "this" is wrong
   *      $p('bar').observe('click', myalert.handleClick.bind(myalert)); // <= RIGHT
   *      // -> If 'bar' is clicked, the alert will be "Clicked!"
   *
   *  `bind` can also *curry* (burn in) arguments for the function if you
   *  provide them after the `context` argument:
   *
   *      var Averager = Class.create({
   *        initialize: function() {
   *          this.count = 0;
   *          this.total = 0;
   *        },
   *        add: function(addend) {
   *          ++this.count;
   *          this.total += addend;
   *        },
   *        getAverage: function() {
   *          return this.count == 0 ? NaN : this.total / this.count;
   *        }
   *      });
   *      var a = new Averager();
   *      var b = new Averager();
   *      var aAdd5 = a.add.bind(a, 5);   // Bind to a, curry 5
   *      var aAdd10 = a.add.bind(a, 10); // Bind to a, curry 10
   *      var bAdd20 = b.add.bind(b, 20); // Bind to b, curry 20
   *      aAdd5();
   *      aAdd10();
   *      bAdd20();
   *      bAdd20();
   *      alert(a.getAverage());
   *      // -> Alerts "7.5" (average of [5, 10])
   *      alert(b.getAverage());
   *      // -> Alerts "20" (average of [20, 20])
   *
   *  (To curry without binding, see [[Function#curry]].)
  **/
  function bind(context) {
    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
    var __method = this, args = slice.call(arguments, 1);
    return function() {
      var a = merge(args, arguments);
      return __method.apply(context, a);
    }
  }

  /** related to: Function#bind
   *  Function#bindAsEventListener(context[, args...]) -> Function
   *  - context (Object): The object to bind to.
   *  - args (?): Optional arguments to curry after the event argument.
   *
   *  An event-specific variant of [[Function#bind]] which ensures the function
   *  will recieve the current event object as the first argument when
   *  executing.
   *
   *  It is not necessary to use `bindAsEventListener` for all bound event
   *  handlers; [[Function#bind]] works well for the vast majority of cases.
   *  `bindAsEventListener` is only needed when:
   *
   *  - Using old-style DOM0 handlers rather than handlers hooked up via
   *    [[Event.observe]], because `bindAsEventListener` gets the event object
   *    from the right place (even on MSIE). (If you're using `Event.observe`,
   *    that's already handled.)
   *  - You want to bind an event handler and curry additional arguments but
   *    have those arguments appear after, rather than before, the event object.
   *    This mostly happens if the number of arguments will vary, and so you
   *    want to know the event object is the first argument.
   *
   *  ##### Example
   *
   *      var ContentUpdater = Class.create({
   *        initialize: function(initialData) {
   *          this.data = Object.extend({}, initialData);
   *        },
   *        // On an event, update the content in the elements whose
   *        // IDs are passed as arguments from our data
   *        updateTheseHandler: function(event) {
   *          var argIndex, id, element;
   *          event.stop();
   *          for (argIndex = 1; argIndex < arguments.length; ++argIndex) {
   *            id = arguments[argIndex];
   *            element = $p(id);
   *            if (element) {
   *              element.update(String(this.data[id]).escapeHTML());
   *            }
   *          }
   *        }
   *      });
   *      var cu = new ContentUpdater({
   *        dispName: 'Joe Bloggs',
   *        dispTitle: 'Manager <provisional>',
   *        dispAge: 47
   *      });
   *      // Using bindAsEventListener because of the variable arg lists:
   *      $p('btnUpdateName').observe('click',
   *        cu.updateTheseHandler.bindAsEventListener(cu, 'dispName')
   *      );
   *      $p('btnUpdateAll').observe('click',
   *        cu.updateTheseHandler.bindAsEventListener(cu, 'dispName', 'dispTitle', 'dispAge')
   *      );
  **/
  function bindAsEventListener(context) {
    var __method = this, args = slice.call(arguments, 1);
    return function(event) {
      var a = update([event || window.event], args);
      return __method.apply(context, a);
    }
  }

  /**
   *  Function#curry(args...) -> Function
   *  - args (?): The arguments to curry.
   *
   *  *Curries* (burns in) arguments to a function, returning a new function
   *  that when called with call the original passing in the curried arguments
   *  (along with any new ones):
   *
   *      function showArguments() {
   *        alert($A(arguments).join(', '));
   *      }
   *      showArguments(1, 2,, 3);
   *      // -> alerts "1, 2, 3"
   *
   *      var f = showArguments.curry(1, 2, 3);
   *      f('a', 'b');
   *      // -> alerts "1, 2, 3, a, b"
   *
   *  [[Function#curry]] works just like [[Function#bind]] without the initial
   *  context argument. Use `bind` if you need to curry arguments _and_ set
   *  context at the same time.
   *
   *  The name "curry" comes from [mathematics](http://en.wikipedia.org/wiki/Currying).
  **/
  function curry() {
    if (!arguments.length) return this;
    var __method = this, args = slice.call(arguments, 0);
    return function() {
      var a = merge(args, arguments);
      return __method.apply(this, a);
    }
  }

  /**
   *  Function#delay(timeout[, args...]) -> Number
   *  - timeout (Number): The time, in seconds, to wait before calling the
   *    function.
   *  - args (?): Optional arguments to pass to the function when calling it.
   *
   *  Schedules the function to run after the specified amount of time, passing
   *  any arguments given.
   *
   *  Behaves much like `window.setTimeout`, but the timeout is in seconds
   *  rather than milliseconds. Returns an integer ID that can be used to
   *  clear the timeout with `window.clearTimeout` before it runs.
   *
   *  To schedule a function to run as soon as the interpreter is idle, use
   *  [[Function#defer]].
   *
   *  ##### Example
   *
   *      function showMsg(msg) {
   *        alert(msg);
   *      }
   *      showMsg.delay(0.1, "Hi there!");
   *      // -> Waits a 10th of a second, then alerts "Hi there!"
  **/
  function delay(timeout) {
    var __method = this, args = slice.call(arguments, 1);
    timeout = timeout * 1000;
    return window.setTimeout(function() {
      return __method.apply(__method, args);
    }, timeout);
  }

  /**
   *  Function#defer(args...) -> Number
   *  - args (?): Optional arguments to pass into the function.
   *
   *  Schedules the function to run as soon as the interpreter is idle.
   *
   *  A "deferred" function will not run immediately; rather, it will run as soon
   *  as the interpreter's call stack is empty.
   *
   *  Behaves much like `window.setTimeout` with a delay set to `0`. Returns an
   *  ID that can be used to clear the timeout with `window.clearTimeout` before
   *  it runs.
   *
   *  ##### Example
   *
   *      function showMsg(msg) {
   *        alert(msg);
   *      }
   *
   *      showMsg("One");
   *      showMsg.defer("Two");
   *      showMsg("Three");
   *      // Alerts "One", then "Three", then (after a brief pause) "Two"
   *      // Note that "Three" happens before "Two"
  **/
  function defer() {
    var args = update([0.01], arguments);
    return this.delay.apply(this, args);
  }

  /**
   *  Function#wrap(wrapper) -> Function
   *  - wrapper (Function): The function to use as a wrapper.
   *
   *  Returns a function "wrapped" around the original function.
   *
   *  [[Function#wrap]] distills the essence of aspect-oriented programming into
   *  a single method, letting you easily build on existing functions by
   *  specifying before and after behavior, transforming the return value, or
   *  even preventing the original function from being called.
   *
   *  The wraper function is called with this signature:
   *
   *      function wrapper(callOriginal[, args...])
   *
   *  ...where `callOriginal` is a function that can be used to call the
   *  original (wrapped) function (or not, as appropriate). (`callOriginal` is
   *  not a direct reference to the original function, there's a layer of
   *  indirection in-between that sets up the proper context \[`this` value\] for
   *  it.)
   *
   *  ##### Example
   *
   *      // Wrap String#capitalize so it accepts an additional argument
   *      String.prototype.capitalize = String.prototype.capitalize.wrap(
   *        function(callOriginal, eachWord) {
   *          if (eachWord && this.include(" ")) {
   *            // capitalize each word in the string
   *            return this.split(" ").invoke("capitalize").join(" ");
   *          } else {
   *            // proceed using the original function
   *            return callOriginal();
   *          }
   *        });
   *
   *      "hello world".capitalize();
   *      // -> "Hello world" (only the 'H' is capitalized)
   *      "hello world".capitalize(true);
   *      // -> "Hello World" (both 'H' and 'W' are capitalized)
  **/
  function wrap(wrapper) {
    var __method = this;
    return function() {
      var a = update([__method.bind(this)], arguments);
      return wrapper.apply(this, a);
    }
  }

  /**
   *  Function#methodize() -> Function
   *
   *  Wraps the function inside another function that, when called, pushes
   *  `this` to the original function as the first argument (with any further
   *  arguments following it).
   *
   *  The `methodize` method transforms the original function that has an
   *  explicit first argument to a function that passes `this` (the current
   *  context) as an implicit first argument at call time. It is useful when we
   *  want to transform a function that takes an object to a method of that
   *  object or its prototype, shortening its signature by one argument.
   *
   *  ##### Example
   *
   *      // A function that sets a name on a target object
   *      function setName(target, name) {
   *        target.name = name;
   *      }
   *
   *      // Use it
   *      obj = {};
   *      setName(obj, 'Fred');
   *      obj.name;
   *      // -> "Fred"
   *
   *      // Make it a method of the object
   *      obj.setName = setName.methodize();
   *
   *      // Use the method instead
   *      obj.setName('Barney');
   *      obj.name;
   *      // -> "Barney"
   *
   *  The example above is quite simplistic. It's more useful to copy methodized
   *  functions to object prototypes so that new methods are immediately shared
   *  among instances. In the Prototype library, `methodize` is used in various
   *  places such as the DOM module, so that (for instance) you can hide an
   *  element either by calling the static version of `Element.hide` and passing in
   *  an element reference or ID, like so:
   *
   *      Element.hide('myElement');
   *
   *  ...or if you already have an element reference, just calling the
   *  methodized form instead:
   *
   *      myElement.hide();
  **/
  function methodize() {
    if (this._methodized) return this._methodized;
    var __method = this;
    return this._methodized = function() {
      var a = update([this], arguments);
      return __method.apply(null, a);
    };
  }

  return {
    argumentNames:       argumentNames,
    bind:                bind,
    bindAsEventListener: bindAsEventListener,
    curry:               curry,
    delay:               delay,
    defer:               defer,
    wrap:                wrap,
    methodize:           methodize
  }
})());

/** section: Language
 * mixin Enumerable
 *
 *  [[Enumerable]] provides a large set of useful methods for enumerations &mdash;
 *  objects that act as collections of values. It is a cornerstone of
 *  Prototype.
 *
 *  [[Enumerable]] is a _mixin_: a set of methods intended not for standaone
 *  use, but for incorporation into other objects.
 *
 *  Prototype mixes [[Enumerable]] into several classes. The most visible cases
 *  are [[Array]] and [[Hash]], but you'll find it in less obvious spots as
 *  well, such as in [[ObjectRange]] and various DOM- or Ajax-related objects.
 *
 *  ##### The `context` parameter
 *
 *  Every method of [[Enumerable]] that takes an iterator also takes the "context
 *  object" as the next (optional) parameter. The context object is what the
 *  iterator will be _bound_ to &mdash; what the keyword `this` will refer to inside
 *  the iterator.
 *
 *      var myObject = {};
 *
 *      ['foo', 'bar', 'baz'].each(function(name, index) {
 *        this[name] = index;
 *      }, myObject); // we have specified the context
 *
 *      myObject;
 *      // -> { foo: 0, bar: 1, baz: 2}
 *
 *  If there is no `context` argument, the iterator function will execute in
 *  the scope from which the [[Enumerable]] method itself was called.
 *
 *  ##### Mixing [[Enumerable]] into your own objects
 *
 *  So, let's say you've created your very own collection-like object (say,
 *  some sort of Set, or perhaps something that dynamically fetches data
 *  ranges from the server side, lazy-loading style). You want to be able to
 *  mix [[Enumerable]] in (and we commend you for it). How do you go about this?
 *
 *  The Enumerable module basically makes only one requirement on your object:
 *  it must provide a method named `_each` (note the leading underscore) that
 *  will accept a function as its unique argument, and will contain the actual
 *  "raw iteration" algorithm, invoking its argument with each element in turn.
 *
 *  As detailed in the documentation for [[Enumerable#each]], [[Enumerable]]
 *  provides all the extra layers (handling iteration short-circuits, passing
 *  numeric indices, etc.). You just need to implement the actual iteration,
 *  as fits your internal structure.
 *
 *  If you're still confused, just have a look at the Prototype source code for
 *  [[Array]], [[Hash]], or [[ObjectRange]]. They all begin with their own
 *  `_each` method, which should help you grasp the idea.
 *
 *  Once you're done with this, you just need to mix [[Enumerable]] in, which
 *  you'll usually do before defining your methods, so as to make sure whatever
 *  overrides you provide for [[Enumerable]] methods will indeed prevail. In
 *  short, your code will probably end up looking like this:
 *
 *
 *      var YourObject = Class.create(Enumerable, {
 *        initialize: function() { // with whatever constructor arguments you need
 *          // Your construction code
 *        },
 *
 *        _each: function(iterator) {
 *          // Your iteration code, invoking iterator at every turn
 *        },
 *
 *        // Your other methods here, including Enumerable overrides
 *      });
 *
 *  Then, obviously, your object can be used like this:
 *
 *      var obj = new YourObject();
 *      // Populate the collection somehow
 *      obj.pluck('somePropName');
 *      obj.invoke('someMethodName');
 *      obj.size();
 *      // etc.
 *
**/

var $break = { };

var Enumerable = (function() {
  /**
   *  Enumerable#each(iterator[, context]) -> Enumerable
   *  - iterator (Function): A `Function` that expects an item in the
   *    collection as the first argument and a numerical index as the second.
   *  - context (Object): The scope in which to call `iterator`. Affects what
   *    the keyword `this` means inside `iterator`.
   *
   *  Calls `iterator` for each item in the collection.
   *
   *  ##### Examples
   *
   *      ['one', 'two', 'three'].each(alert);
   *      // Alerts "one", then alerts "two", then alerts "three"
   *
   *  ##### Built-In Variants
   *
   *  Most of the common use cases for `each` are already available pre-coded
   *  as other methods on [[Enumerable]]. Whether you want to find the first
   *  matching item in an enumeration, or transform it, or determine whether it
   *  has any (or all) values matching a particular condition, [[Enumerable]]
   *  has a method to do that for you.
  **/
  function each(iterator, context) {
    var index = 0;
    try {
      this._each(function(value) {
        iterator.call(context, value, index++);
      });
    } catch (e) {
      if (e != $break) throw e;
    }
    return this;
  }

  /**
   *  Enumerable#eachSlice(number[, iterator = Prototype.K[, context]]) -> Enumerable
   *  - number (Number): The number of items to include in each slice.
   *  - iterator (Function): An optional function to use to transform each
   *    element before it's included in the slice; if this is not provided,
   *    the element itself is included.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Groups items into chunks of the given size. The final "slice" may have
   *  fewer than `number` items; it won't "pad" the last group with empty
   *  values. For that behavior, use [[Enumerable#inGroupsOf]].
   *
   *  ##### Example
   *
   *      var students = [
   *        { name: 'Sunny', age: 20 },
   *        { name: 'Audrey', age: 21 },
   *        { name: 'Matt', age: 20 },
   *        { name: 'Amelie', age: 26 },
   *        { name: 'Will', age: 21 }
   *      ];
   *
   *      students.eachSlice(3, function(student) {
   *        return student.name;
   *      });
   *      // -> [['Sunny', 'Audrey', 'Matt'], ['Amelie', 'Will']]
  **/
  function eachSlice(number, iterator, context) {
    var index = -number, slices = [], array = this.toArray();
    if (number < 1) return array;
    while ((index += number) < array.length)
      slices.push(array.slice(index, index+number));
    return slices.collect(iterator, context);
  }

  /**
   *  Enumerable#all([iterator = Prototype.K[, context]]) -> Boolean
   *  - iterator (Function): An optional function to use to evaluate
   *    each element in the enumeration; the function should return the value to
   *    test. If this is not provided, the element itself is tested.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Determines whether all the elements are "truthy" (boolean-equivalent to
   *  `true`), either directly or through computation by the provided iterator.
   *  Stops on the first falsy element found (e.g., the first element that
   *  is boolean-equivalent to `false`, such as `undefined`, `0`, or indeed
   *  `false`);
   *
   *  ##### Examples
   *
   *      [].all();
   *      // -> true (empty arrays have no elements that could be falsy)
   *
   *      $R(1, 5).all();
   *      // -> true (all values in [1..5] are truthy)
   *
   *      [0, 1, 2].all();
   *      // -> false (with only one loop cycle: 0 is falsy)
   *
   *      [9, 10, 15].all(function(n) { return n >= 10; });
   *      // -> false (the iterator returns false on 9)
  **/
  function all(iterator, context) {
    iterator = iterator || Prototype.K;
    var result = true;
    this.each(function(value, index) {
      result = result && !!iterator.call(context, value, index);
      if (!result) throw $break;
    });
    return result;
  }

  /**
   *  Enumerable#any([iterator = Prototype.K[, context]]) -> Boolean
   *  - iterator (Function): An optional function to use to evaluate each
   *    element in the enumeration; the function should return the value to
   *    test. If this is not provided, the element itself is tested.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Determines whether at least one element is truthy (boolean-equivalent to
   *  `true`), either directly or through computation by the provided iterator.
   *
   *  ##### Examples
   *
   *      [].any();
   *      // -> false (empty arrays have no elements that could be truthy)
   *
   *      $R(0, 2).any();
   *      // -> true (on the second loop, 1 is truthy)
   *
   *      [2, 4, 6, 8, 10].any(function(n) { return n > 5; });
   *      // -> true (the iterator will return true on 6)
  **/
  function any(iterator, context) {
    iterator = iterator || Prototype.K;
    var result = false;
    this.each(function(value, index) {
      if (result = !!iterator.call(context, value, index))
        throw $break;
    });
    return result;
  }

  /**
   *  Enumerable#collect([iterator = Prototype.K[, context]]) -> Array
   *  - iterator (Function): The iterator function to apply to each element
   *    in the enumeration.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Returns the result of applying `iterator` to each element. If no
   *  `iterator` is provided, the elements are simply copied to the
   *  returned array.
   *
   *  ##### Examples
   *
   *      ['Hitch', "Hiker's", 'Guide', 'to', 'the', 'Galaxy'].collect(function(s) {
   *        return s.charAt(0).toUpperCase();
   *      });
   *      // -> ['H', 'H', 'G', 'T', 'T', 'G']
   *
   *      $R(1,5).collect(function(n) {
   *        return n * n;
   *      });
   *      // -> [1, 4, 9, 16, 25]
  **/
  function collect(iterator, context) {
    iterator = iterator || Prototype.K;
    var results = [];
    this.each(function(value, index) {
      results.push(iterator.call(context, value, index));
    });
    return results;
  }

  /**
   *  Enumerable#detect(iterator[, context]) -> firstElement | undefined
   *  - iterator (Function): The iterator function to apply to each element
   *    in the enumeration.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Returns the first element for which the iterator returns a truthy value.
   *  Aliased by the [[Enumerable#find]] method.
   *
   *  ##### Example
   *
   *      [1, 7, -2, -4, 5].detect(function(n) { return n < 0; });
   *      // -> -2
  **/
  function detect(iterator, context) {
    var result;
    this.each(function(value, index) {
      if (iterator.call(context, value, index)) {
        result = value;
        throw $break;
      }
    });
    return result;
  }

  /**
   *  Enumerable#findAll(iterator[, context]) -> Array
   *  - iterator (Function): An iterator function to use to test the elements.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Returns all the elements for which the iterator returned a truthy value.
   *  For the opposite operation, see [[Enumerable#reject]].
   *
   *  ##### Example
   *
   *      [1, 'two', 3, 'four', 5].findAll(Object.isString);
   *      // -> ['two', 'four']
  **/
  function findAll(iterator, context) {
    var results = [];
    this.each(function(value, index) {
      if (iterator.call(context, value, index))
        results.push(value);
    });
    return results;
  }

  /**
   *  Enumerable#grep(filter[, iterator = Prototype.K[, context]]) -> Array
   *  - filter (RegExp | String | Object): The filter to apply to elements. This
   *    can be a `RegExp` instance, a regular expression [[String]], or any
   *    object with a `match` function.
   *  - iterator (Function): An optional function to apply to selected elements
   *    before including them in the result.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Returns an array containing all of the elements for which the given
   *  filter returns `true` (or a truthy value). If an iterator is provided,
   *  it is used to produce the returned value for each selected element; this
   *  is done *after* the element has been selected by the filter.
   *
   *  If the given filter is a [[String]], it is converted into a `RegExp`
   *  object. To select elements, each element is passed into the filter's
   *  `match` function, which should return a truthy value to select the element
   *  or a falsy value not to. Note that the `RegExp` `match` function will
   *  convert elements to Strings to perform matching.
   *
   *  ##### Examples
   *
   *      // Get all strings containing a repeated letter
   *      ['hello', 'world', 'this', 'is', 'cool'].grep(/(.)\1/);
   *      // -> ['hello', 'cool']
   *
   *      // Get all numbers ending with 0 or 5 and subtract 1 from them
   *      $R(1, 30).grep(/[05]$/, function(n) { return n - 1; });
   *      // -> [4, 9, 14, 19, 24, 29]
  **/
  function grep(filter, iterator, context) {
    iterator = iterator || Prototype.K;
    var results = [];

    if (Object.isString(filter))
      filter = new RegExp(RegExp.escape(filter));

    this.each(function(value, index) {
      if (filter.match(value))
        results.push(iterator.call(context, value, index));
    });
    return results;
  }

  /**
   *  Enumerable#include(object) -> Boolean
   *  - object (?): The object to look for.
   *
   *  Determines whether a given object is in the enumerable or not,
   *  based on the `==` comparison operator (equality with implicit type
   *  conversion).
   *
   *  ##### Examples
   *
   *      $R(1, 15).include(10);
   *      // -> true
   *
   *      ['hello', 'world'].include('HELLO');
   *      // -> false ('hello' != 'HELLO')
   *
   *      [1, 2, '3', '4', '5'].include(3);
   *      // -> true ('3' == 3)
  **/
  function include(object) {
    if (Object.isFunction(this.indexOf))
      if (this.indexOf(object) != -1) return true;

    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  }

  /**
   *  Enumerable#inGroupsOf(number[, fillWith = null]) -> [group...]
   *  - number (Number): The number of items to include in each group.
   *  - fillWith (Object): An optional filler to use if the last group needs
   *    any; defaults to `null`.
   *
   *  Like [[Enumerable#eachSlice]], but pads out the last chunk with the
   *  specified value if necessary and doesn't support the `iterator` function.
   *
   *  ##### Examples
   *
   *      var students = [
   *        { name: 'Sunny',  age: 20 },
   *        { name: 'Audrey', age: 21 },
   *        { name: 'Matt',   age: 20 },
   *        { name: 'Amelie', age: 26 },
   *        { name: 'Will',   age: 21 }
   *      ];
   *
   *      students.inGroupsOf(2, { name: '', age: 0 });
   *      // -> [
   *      //      [{ name: 'Sunny', age: 20 }, { name: 'Audrey', age: 21 }],
   *      //      [{ name: 'Matt', age: 20 },  { name: 'Amelie', age: 26 }],
   *      //      [{ name: 'Will', age: 21 },  { name: '', age: 0 }]
   *      //    ]
  **/
  function inGroupsOf(number, fillWith) {
    fillWith = Object.isUndefined(fillWith) ? null : fillWith;
    return this.eachSlice(number, function(slice) {
      while(slice.length < number) slice.push(fillWith);
      return slice;
    });
  }

  /**
   *  Enumerable#inject(accumulator, iterator[, context]) -> accumulatedValue
   *  - accumulator (?): The initial value to which the `iterator` adds.
   *  - iterator (Function): An iterator function used to build the accumulated
   *    result.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Incrementally builds a result value based on the successive results
   *  of the iterator. This can be used for array construction, numerical
   *  sums/averages, etc.
   *
   *  The `iterator` function is called once for each element in the
   *  enumeration, receiving the current value of the accumulator as its first
   *  argument, the element as its second argument, and the element's index as
   *  its third. It returns the new value for the accumulator.
   *
   *  ##### Examples
   *
   *      $R(1,10).inject(0, function(acc, n) { return acc + n; });
   *      // -> 55 (sum of 1 to 10)
   *
   *      ['a', 'b', 'c', 'd', 'e'].inject([], function(string, value, index) {
   *        if (index % 2 === 0) { // even numbers
   *          string += value;
   *        }
   *        return string;
   *      });
   *      // -> 'ace'
  **/
  function inject(memo, iterator, context) {
    this.each(function(value, index) {
      memo = iterator.call(context, memo, value, index);
    });
    return memo;
  }

  /**
   *  Enumerable#invoke(methodName[, arg...]) -> Array
   *  - methodName (String): The name of the method to invoke.
   *  - args (?): Optional arguments to pass to the method.
   *
   *  Invokes the same method, with the same arguments, for all items in a
   *  collection. Returns an array of the results of the method calls.
   *
   *  ##### Examples
   *
   *      ['hello', 'world'].invoke('toUpperCase');
   *      // -> ['HELLO', 'WORLD']
   *
   *      ['hello', 'world'].invoke('substring', 0, 3);
   *      // -> ['hel', 'wor']
   *
   *      $$('input').invoke('stopObserving', 'change');
   *      // -> Stops observing the 'change' event on all input elements,
   *      // returns an array of the element references.
  **/
  function invoke(method) {
    var args = $A(arguments).slice(1);
    return this.map(function(value) {
      return value[method].apply(value, args);
    });
  }

  /** related to: Enumerable#min
   *  Enumerable#max([iterator = Prototype.K[, context]]) -> maxValue
   *  - iterator (Function): An optional function to use to evaluate each
   *    element in the enumeration; the function should return the value to
   *    test. If this is not provided, the element itself is tested.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Returns the maximum element (or element-based `iterator` result), or
   *  `undefined` if the enumeration is empty. Elements are either compared
   *  directly, or by first calling `iterator` and comparing returned values.
   *  If multiple "max" elements (or results) are equivalent, the one closest
   *  to the end of the enumeration is returned.
   *
   *  If provided, `iterator` is called with two arguments: The element being
   *  evaluated, and its index in the enumeration; it should return the value
   *  `max` should consider (and potentially return).
   *
   *  ##### Examples
   *
   *      ['c', 'b', 'a'].max();
   *      // -> 'c'
   *
   *      [1, 3, '3', 2].max();
   *      // -> '3' (because both 3 and '3' are "max", and '3' was later)
   *
   *      ['zero', 'one', 'two'].max(function(item) { return item.length; });
   *      // -> 4
  **/
  function max(iterator, context) {
    iterator = iterator || Prototype.K;
    var result;
    this.each(function(value, index) {
      value = iterator.call(context, value, index);
      if (result == null || value >= result)
        result = value;
    });
    return result;
  }

  /** related to: Enumerable#max
   *  Enumerable#min([iterator = Prototype.K[, context]]) -> minValue
   *  - iterator (Function): An optional function to use to evaluate each
   *    element in the enumeration; the function should return the value to
   *    test. If this is not provided, the element itself is tested.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Returns the minimum element (or element-based `iterator` result), or
   *  `undefined` if the enumeration is empty. Elements are either compared
   *  directly, or by first calling `iterator` and comparing returned values.
   *  If multiple "min" elements (or results) are equivalent, the one closest
   *  to the *beginning* of the enumeration is returned.
   *
   *  If provided, `iterator` is called with two arguments: The element being
   *  evaluated, and its index in the enumeration; it should return the value
   *  `min` should consider (and potentially return).
   *
   *  ##### Examples
   *
   *      ['c', 'b', 'a'].min();
   *      // -> 'a'
   *
   *      [3, 1, '1', 2].min();
   *      // -> 1 (because both 1 and '1' are "min", and 1 was earlier)
   *
   *      ['un', 'deux', 'trois'].min(function(item) { return item.length; });
   *      // -> 2
  **/
  function min(iterator, context) {
    iterator = iterator || Prototype.K;
    var result;
    this.each(function(value, index) {
      value = iterator.call(context, value, index);
      if (result == null || value < result)
        result = value;
    });
    return result;
  }

  /**
   *  Enumerable#partition([iterator = Prototype.K[, context]]) -> [TrueArray, FalseArray]
   *  - iterator (Function): An optional function to use to evaluate each
   *    element in the enumeration; the function should return the value to
   *    test. If this is not provided, the element itself is tested.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Partitions the elements in two groups: those regarded as true, and those
   *  considered false. By default, regular JavaScript boolean equivalence
   *  (e.g., truthiness vs. falsiness) is used, but an iterator can be provided
   *  that computes a boolean representation of the elements.
   *
   *  Using `partition` is more efficient than using [[Enumerable#findAll]] and
   *  then using [[Enumerable#reject]] because the enumeration is only processed
   *  once.
   *
   *  ##### Examples
   *
   *      ['hello', null, 42, false, true, , 17].partition();
   *      // -> [['hello', 42, true, 17], [null, false, undefined]]
   *
   *      $R(1, 10).partition(function(n) {
   *        return 0 == n % 2;
   *      });
   *      // -> [[2, 4, 6, 8, 10], [1, 3, 5, 7, 9]]
  **/
  function partition(iterator, context) {
    iterator = iterator || Prototype.K;
    var trues = [], falses = [];
    this.each(function(value, index) {
      (iterator.call(context, value, index) ?
        trues : falses).push(value);
    });
    return [trues, falses];
  }

  /**
   *  Enumerable#pluck(property) -> Array
   *  - property (String): The name of the property to fetch.
   *
   *  Pre-baked implementation for a common use-case of [[Enumerable#collect]]
   *  and [[Enumerable#each]]: fetching the same property for all of the
   *  elements. Returns an array of the property values.
   *
   *  ##### Example
   *
   *      ['hello', 'world', 'this', 'is', 'nice'].pluck('length');
   *      // -> [5, 5, 4, 2, 4]
  **/
  function pluck(property) {
    var results = [];
    this.each(function(value) {
      results.push(value[property]);
    });
    return results;
  }

  /**
   *  Enumerable#reject(iterator[, context]) -> Array
   *  - iterator (Function): An iterator function to use to test the elements.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Returns all the elements for which the iterator returns a falsy value.
   *  For the opposite operation, see [[Enumerable#findAll]].
   *
   *  ##### Example
   *
   *      [1, "two", 3, "four", 5].reject(Object.isString);
   *      // -> [1, 3, 5]
  **/
  function reject(iterator, context) {
    var results = [];
    this.each(function(value, index) {
      if (!iterator.call(context, value, index))
        results.push(value);
    });
    return results;
  }

  /**
   *  Enumerable#sortBy(iterator[, context]) -> Array
   *  - iterator (Function): The function to use to compute the criterion for
   *    each element in the enumeration.
   *  - context (Object): An optional object to use as `this` within
   *    calls to the iterator.
   *
   *  Creates a custom-sorted array of the elements based on the criteria
   *  computed, for each element, by the iterator. Computed criteria must have
   *  well-defined ordering semantics (i.e. the `<` operator must exist between
   *  any two criteria).
   *
   *  [[Enumerable#sortBy]] does not guarantee a *stable* sort; adjacent
   *  equivalent elements may be swapped.
   *
   *  ##### Example
   *
   *      ['hello', 'world', 'this', 'is', 'nice'].sortBy(function(s) {
   *        return s.length;
   *      });
   *      // -> ['is', 'nice', 'this', 'world', 'hello']
  **/
  function sortBy(iterator, context) {
    return this.map(function(value, index) {
      return {
        value: value,
        criteria: iterator.call(context, value, index)
      };
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? -1 : a > b ? 1 : 0;
    }).pluck('value');
  }

  /**
   *  Enumerable#toArray() -> Array
   *
   *  Returns an Array containing the elements of the enumeration.
   *
   *  ##### Example
   *
   *      $R(1, 5).toArray();
   *      // -> [1, 2, 3, 4, 5]
   *
   *      $H({ name: 'Sunny', age: 20 }).toArray();
   *      // -> [['name', 'Sunny'], ['age', 20]]
  **/
  function toArray() {
    return this.map();
  }

  /**
   *  Enumerable#zip(sequence...[, iterator = Prototype.K]) -> Array
   *  - sequence (Object): A sequence to zip with this enumerable (there can
   *    be several of these if desired).
   *  - iterator (Function): Optional function to use to transform the tuples
   *    once generated; this is always the last argument provided.
   *
   *  Zips together (think of the zipper on a pair of trousers) 2+ sequences,
   *  returning a new array of tuples. Each tuple is an array containing one
   *  value per original sequence. Tuples can be transformed to something else
   *  by applying the optional `iterator` on them.
   *
   *  If supplied, `iterator` is called with each tuple as its only argument
   *  and should return the value to use in place of that tuple.
   *
   *  ##### Examples
   *
   *      var firstNames = ['Jane', 'Nitin', 'Guy'];
   *      var lastNames  = ['Doe',  'Patel', 'Forcier'];
   *      var ages       = [23,     41,      17];
   *
   *      firstNames.zip(lastNames);
   *      // -> [['Jane', 'Doe'], ['Nitin', 'Patel'], ['Guy', 'Forcier']]
   *
   *      firstNames.zip(lastNames, ages);
   *      // -> [['Jane', 'Doe', 23], ['Nitin', 'Patel', 41], ['Guy', 'Forcier', 17]]
   *
   *      firstNames.zip(lastNames, ages, function(tuple) {
   *        return tuple[0] + ' ' + tuple[1] + ' is ' + tuple[2];
   *      });
   *      // -> ['Jane Doe is 23', 'Nitin Patel is 41', 'Guy Forcier is 17']
  **/
  function zip() {
    var iterator = Prototype.K, args = $A(arguments);
    if (Object.isFunction(args.last()))
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      return iterator(collections.pluck(index));
    });
  }

  /**
   *  Enumerable#size() -> Number
   *
   *  Returns the size of the enumeration.
  **/
  function size() {
    return this.toArray().length;
  }

  /**
   *  Enumerable#inspect() -> String
   *
   *  Returns the debug-oriented string representation of the object.
  **/
  function inspect() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
  }

  /** alias of: Enumerable#collect
   *  Enumerable#map([iterator = Prototype.K[, context]]) -> Array
  **/

  /** alias of: Enumerable#any
   *  Enumerable#some([iterator = Prototype.K[, context]]) -> Boolean
  **/

  /** alias of: Enumerable#all
   *  Enumerable#every([iterator = Prototype.K[, context]]) -> Boolean
  **/

  /** alias of: Enumerable#findAll
   *  Enumerable#select(iterator[, context]) -> Array
  **/

  /** alias of: Enumerable#findAll
   *  Enumerable#filter(iterator[, context]) -> Array
  **/

  /** alias of: Enumerable#include
   *  Enumerable#member(object) -> Boolean
  **/

  /** alias of: Enumerable#toArray
   *  Enumerable#entries() -> Array
  **/

  /** alias of: Enumerable#detect
   *  Enumerable#find(iterator[, context]) -> firstElement | undefined
  **/

  return {
    each:       each,
    eachSlice:  eachSlice,
    all:        all,
    every:      all,
    any:        any,
    some:       any,
    collect:    collect,
    map:        collect,
    detect:     detect,
    findAll:    findAll,
    select:     findAll,
    filter:     findAll,
    grep:       grep,
    include:    include,
    member:     include,
    inGroupsOf: inGroupsOf,
    inject:     inject,
    invoke:     invoke,
    max:        max,
    min:        min,
    partition:  partition,
    pluck:      pluck,
    reject:     reject,
    sortBy:     sortBy,
    toArray:    toArray,
    entries:    toArray,
    zip:        zip,
    size:       size,
    inspect:    inspect,
    find:       detect
  };
})();
/** section: Language, related to: Array
 *  $A(iterable) -> Array
 *  
 *  Accepts an array-like collection (anything with numeric indices) and returns
 *  its equivalent as an actual [[Array]] object. This method is a convenience
 *  alias of [[Array.from]], but is the preferred way of casting to an [[Array]].
 *  
 *  The primary use of [[$A]] is to obtain an actual [[Array]] object based on
 *  anything that could pass as an array (e.g. the `NodeList` or
 *  `HTMLCollection` objects returned by numerous DOM methods, or the predefined
 *  `arguments` reference within your functions).
 *  
 *  The reason you would want an actual [[Array]] is simple:
 *  [[Array Prototype extends Array]] to equip it with numerous extra methods,
 *  and also mixes in the [[Enumerable]] module, which brings in another
 *  boatload of nifty methods. Therefore, in Prototype, actual [[Array]]s trump
 *  any other collection type you might otherwise get.
 *  
 *  The conversion performed is rather simple: `null`, `undefined` and `false` become
 *  an empty array; any object featuring an explicit `toArray` method (as many Prototype
 *  objects do) has it invoked; otherwise, we assume the argument "looks like an array"
 *  (e.g. features a `length` property and the `[]` operator), and iterate over its components
 *  in the usual way.
 *  
 *  When passed an array, [[$A]] _makes a copy_ of that array and returns it.
 *  
 *  ##### Examples
 *  
 *  The well-known DOM method [`document.getElementsByTagName()`](http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-A6C9094)
 *  doesn't return an [[Array]], but a `NodeList` object that implements the basic array
 *  "interface." Internet Explorer does not allow us to extend `Enumerable` onto `NodeList.prototype`,
 *  so instead we cast the returned `NodeList` to an [[Array]]:
 *  
 *      var paras = $A(document.getElementsByTagName('p'));
 *      paras.each(Element.hide);
 *      $p(paras.last()).show();
 *  
 *  Notice we had to use [[Enumerable#each each]] and [[Element.hide]] because
 *  [[$A]] doesn't perform DOM extensions, since the array could contain
 *  anything (not just DOM elements). To use the [[Element#hide]] instance
 *  method we first must make sure all the target elements are extended:
 *  
 *      $A(document.getElementsByTagName('p')).map(Element.extend).invoke('hide');
 *  
 *  Want to display your arguments easily? [[Array]] features a `join` method, but the `arguments`
 *  value that exists in all functions *does not* inherit from [[Array]]. So, the tough
 *  way, or the easy way?
 *  
 *      // The hard way...
 *      function showArgs() {
 *        alert(Array.prototype.join.call(arguments, ', '));
 *      }
 *      
 *      // The easy way...
 *      function showArgs() {
 *        alert($A(arguments).join(', '));
 *      }
**/

function $A(iterable) {
  if (!iterable) return [];
  // Safari <2.0.4 crashes when accessing property of a node list with property accessor.
  // It nevertheless works fine with `in` operator, which is why we use it here
  if ('toArray' in Object(iterable)) return iterable.toArray();
  var length = iterable.length || 0, results = new Array(length);
  while (length--) results[length] = iterable[length];
  return results;
}

/** section: Language, related to: Array
 *  $w(String) -> Array
 *  
 *  Splits a string into an [[Array]], treating all whitespace as delimiters. Equivalent
 *  to Ruby's `%w{foo bar}` or Perl's `qw(foo bar)`.
 *  
 *  This is one of those life-savers for people who just hate commas in literal arrays :-)
 *  
 *  ### Examples
 *  
 *      $w('apples bananas kiwis')
 *      // -> ['apples', 'bananas', 'kiwis']
 *  
 *  This can slightly shorten code when writing simple iterations:
 *  
 *      $w('apples bananas kiwis').each(function(fruit){
 *        var message = 'I like ' + fruit
 *        // do something with the message
 *      })
 *  
 *  This also becomes sweet when combined with [[Element]] functions:
 *  
 *      $w('ads navbar funkyLinks').each(Element.hide);
**/

function $w(string) {
  if (!Object.isString(string)) return [];
  string = string.strip();
  return string ? string.split(/\s+/) : [];
}

/** alias of: $A
 *  Array.from(iterable) -> Array
**/
Array.from = $A;

/** section: Language
 * class Array
 *  includes Enumerable
 *
 *  Prototype extends all native JavaScript arrays with quite a few powerful
 *  methods.
 *
 *  This is done in two ways:
 *
 *  * It mixes in the [[Enumerable]] module, which brings in a ton of methods.
 *  * It adds quite a few extra methods, which are documented in this section.
 *
 *  With Prototype, arrays become much, much more than the trivial objects we
 *  used to manipulate, limiting ourselves to using their `length` property and
 *  their `[]` indexing operator. They become very powerful objects that
 *  greatly simplify the code for 99% of the common use cases involving them.
 *
 *  ##### Why you should stop using for...in to iterate
 *
 *  Many JavaScript authors have been misled into using the `for...in` JavaScript
 *  construct to loop over array elements. This kind of code just won't work
 *  with Prototype.
 *
 *  The ECMA 262 standard, which defines ECMAScript 3rd edition, supposedly
 *  implemented by all major browsers including MSIE, defines ten methods
 *  on [[Array]] (&sect;15.4.4), including nice methods like `concat`, `join`,
 *  `pop`, and `push`.
 *
 *  This same standard explicitly defines that the `for...in` construct (&sect;12.6.4)
 *  exists to enumerate the properties of the object appearing on the right side
 *  of the `in` keyword. Only properties specifically marked as _non-enumerable_
 *  are ignored by such a loop. By default, the `prototype` and `length`
 *  properties are so marked, which prevents you from enumerating over array
 *  methods when using for...in. This comfort led developers to use `for...in` as a
 *  shortcut for indexing loops, when it is not its actual purpose.
 *
 *  However, Prototype has no way to mark the methods it adds to
 *  `Array.prototype` as non-enumerable. Therefore, using `for...in` on arrays
 *  when using Prototype will enumerate all extended methods as well, such as
 *  those coming from the [[Enumerable]] module, and those Prototype puts in the
 *  [[Array]] namespace (listed further below).
 *
 *  ##### What you should use instead
 *
 *  You can revert to vanilla loops:
 *
 *      for (var index = 0; index < myArray.length; ++index) {
 *        var item = myArray[index];
 *        // Your code working on item here...
 *      }
 *
 *  Or you can use iterators, such as [[Array#each]]:
 *
 *      myArray.each(function(item) {
 *        // Your code working on item here...
 *      });
 *
 *  The inability to use `for...in` on arrays is not much of a burden: as you'll
 *  see, most of what you used to loop over arrays for can be concisely done
 *  using the new methods provided by Array or the mixed-in [[Enumerable]]
 *  module. So manual loops should be fairly rare.
 *
 *  ##### A note on performance
 *
 *  Should you have a very large array, using iterators with lexical closures
 *  (anonymous functions that you pass to the iterators and that get invoked at
 *  every loop iteration) in methods like [[Array#each]] &mdash; _or_ relying on
 *  repetitive array construction (such as uniq), may yield unsatisfactory
 *  performance. In such cases, you're better off writing manual indexing loops,
 *  but take care then to cache the length property and use the prefix `++`
 *  operator:
 *
 *      // Custom loop with cached length property: maximum full-loop
 *      // performance on very large arrays!
 *      for (var index = 0, len = myArray.length; index < len; ++index) {
 *        var item = myArray[index];
 *        // Your code working on item here...
 *      }
 *
**/

(function() {
  var arrayProto = Array.prototype,
      slice = arrayProto.slice,
      _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available

  function each(iterator, context) {
    for (var i = 0, length = this.length >>> 0; i < length; i++) {
      if (i in this) iterator.call(context, this[i], i, this);
    }
  }
  if (!_each) _each = each;
  
  /**
   *  Array#clear() -> Array
   *
   *  Clears the array (makes it empty) and returns the array reference.
   *
   *  ##### Example
   *
   *      var guys = ['Sam', 'Justin', 'Andrew', 'Dan'];
   *      guys.clear();
   *      // -> []
   *      guys
   *      // -> []
  **/
  function clear() {
    this.length = 0;
    return this;
  }

  /**
   *  Array#first() -> ?
   *
   *  Returns the array's first item (e.g., `array[0]`).
  **/
  function first() {
    return this[0];
  }

  /**
   *  Array#last() -> ?
   *
   *  Returns the array's last item (e.g., `array[array.length - 1]`).
  **/
  function last() {
    return this[this.length - 1];
  }

  /**
   *  Array#compact() -> Array
   *
   *  Returns a **copy** of the array without any `null` or `undefined` values.
   *
   *  ##### Example
   *
   *      var orig = [undefined, 'A', undefined, 'B', null, 'C'];
   *      var copy = orig.compact();
   *      // orig -> [undefined, 'A', undefined, 'B', null, 'C'];
   *      // copy -> ['A', 'B', 'C'];
  **/
  function compact() {
    return this.select(function(value) {
      return value != null;
    });
  }

  /**
   *  Array#flatten() -> Array
   *
   *  Returns a flattened (one-dimensional) copy of the array, leaving
   *  the original array unchanged.
   *
   *  Nested arrays are recursively injected inline. This can prove very
   *  useful when handling the results of a recursive collection algorithm,
   *  for instance.
   *
   *  ##### Example
   *
   *      var a = ['frank', ['bob', 'lisa'], ['jill', ['tom', 'sally']]];
   *      var b = a.flatten();
   *      // a -> ['frank', ['bob', 'lisa'], ['jill', ['tom', 'sally']]]
   *      // b -> ['frank', 'bob', 'lisa', 'jill', 'tom', 'sally']
  **/
  function flatten() {
    return this.inject([], function(array, value) {
      if (Object.isArray(value))
        return array.concat(value.flatten());
      array.push(value);
      return array;
    });
  }

  /**
   *  Array#without(value[, value...]) -> Array
   *  - value (?): A value to exclude.
   *
   *  Produces a new version of the array that does not contain any of the
   *  specified values, leaving the original array unchanged.
   *
   *  ##### Examples
   *
   *      [3, 5, 6].without(3)
   *      // -> [5, 6]
   *
   *      [3, 5, 6, 20].without(20, 6)
   *      // -> [3, 5]
  **/
  function without() {
    var values = slice.call(arguments, 0);
    return this.select(function(value) {
      return !values.include(value);
    });
  }

  /**
   *  Array#reverse([inline = true]) -> Array
   *  - inline (Boolean): Whether to modify the array in place. Defaults to `true`.
   *      Clones the original array when `false`.
   *
   *  Reverses the array's contents, optionally cloning it first.
   *
   *  ##### Examples
   *
   *      // Making a copy
   *      var nums = [3, 5, 6, 1, 20];
   *      var rev = nums.reverse(false);
   *      // nums -> [3, 5, 6, 1, 20]
   *      // rev -> [20, 1, 6, 5, 3]
   *
   *      // Working inline
   *      var nums = [3, 5, 6, 1, 20];
   *      nums.reverse();
   *      // nums -> [20, 1, 6, 5, 3]
  **/
  function reverse(inline) {
    return (inline === false ? this.toArray() : this)._reverse();
  }

  /**
   *  Array#uniq([sorted = false]) -> Array
   *  - sorted (Boolean): Whether the array has already been sorted. If `true`,
   *    a less-costly algorithm will be used.
   *
   *  Produces a duplicate-free version of an array. If no duplicates are
   *  found, the original array is returned.
   *
   *  On large arrays when `sorted` is `false`, this method has a potentially
   *  large performance cost.
   *
   *  ##### Examples
   *
   *      [1, 3, 2, 1].uniq();
   *      // -> [1, 2, 3]
   *
   *      ['A', 'a'].uniq();
   *      // -> ['A', 'a'] (because String comparison is case-sensitive)
  **/
  function uniq(sorted) {
    return this.inject([], function(array, value, index) {
      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
        array.push(value);
      return array;
    });
  }

  /**
   *  Array#intersect(array) -> Array
   *  - array (Array): A collection of values.
   *
   *  Returns an array containing every item that is shared between the two
   *  given arrays.
  **/
  function intersect(array) {
    return this.uniq().findAll(function(item) {
      return array.detect(function(value) { return item === value });
    });
  }

  /** alias of: Array#clone
   *  Array#toArray() -> Array
  **/

  /**
   *  Array#clone() -> Array
   *
   *  Returns a duplicate of the array, leaving the original array intact.
  **/
  function clone() {
    return slice.call(this, 0);
  }

  /** related to: Enumerable#size
   *  Array#size() -> Number
   *
   *  Returns the size of the array (e.g., `array.length`).
   *
   *  This is just a local optimization of the mixed-in [[Enumerable#size]]
   *  which avoids array cloning and uses the array's native length property.
  **/
  function size() {
    return this.length;
  }

  /** related to: Object.inspect
   *  Array#inspect() -> String
   *
   *  Returns the debug-oriented string representation of an array.
   *
   *  ##### Example
   *
   *      ['Apples', {good: 'yes', bad: 'no'}, 3, 34].inspect()
   *      // -> "['Apples', [object Object], 3, 34]"
  **/
  function inspect() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  }

  /**
   *  Array#indexOf(item[, offset = 0]) -> Number
   *  - item (?): A value that may or may not be in the array.
   *  - offset (Number): The number of initial items to skip before beginning
   *      the search.
   *
   *  Returns the index of the first occurrence of `item` within the array,
   *  or `-1` if `item` doesn't exist in the array. `Array#indexOf` compares
   *  items using *strict equality* (`===`).
   *
   *  ##### Examples
   *
   *      [3, 5, 6, 1, 20].indexOf(1)
   *      // -> 3
   *
   *      [3, 5, 6, 1, 20].indexOf(90)
   *      // -> -1 (not found)
   *
   *      ['1', '2', '3'].indexOf(1);
   *      // -> -1 (not found, 1 !== '1')
  **/
  function indexOf(item, i) {
    i || (i = 0);
    var length = this.length;
    if (i < 0) i = length + i;
    for (; i < length; i++)
      if (this[i] === item) return i;
    return -1;
  }

  /** related to: Array#indexOf
   *  Array#lastIndexOf(item[, offset]) -> Number
   *  - item (?): A value that may or may not be in the array.
   *  - offset (Number): The number of items at the end to skip before beginning
   *      the search.
   *
   *  Returns the position of the last occurrence of `item` within the array &mdash; or
   *  `-1` if `item` doesn't exist in the array.
  **/
  function lastIndexOf(item, i) {
    i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
    var n = this.slice(0, i).reverse().indexOf(item);
    return (n < 0) ? n : i - n - 1;
  }

  // Replaces a built-in function. No PDoc needed.
  function concat() {
    var array = slice.call(this, 0), item;
    for (var i = 0, length = arguments.length; i < length; i++) {
      item = arguments[i];
      if (Object.isArray(item) && !('callee' in item)) {
        for (var j = 0, arrayLength = item.length; j < arrayLength; j++)
          array.push(item[j]);
      } else {
        array.push(item);
      }
    }
    return array;
  }

  Object.extend(arrayProto, Enumerable);

  if (!arrayProto._reverse)
    arrayProto._reverse = arrayProto.reverse;

  Object.extend(arrayProto, {
    _each:     _each,
    clear:     clear,
    first:     first,
    last:      last,
    compact:   compact,
    flatten:   flatten,
    without:   without,
    reverse:   reverse,
    uniq:      uniq,
    intersect: intersect,
    clone:     clone,
    toArray:   clone,
    size:      size,
    inspect:   inspect
  });

  // fix for opera
  var CONCAT_ARGUMENTS_BUGGY = (function() {
    return [].concat(arguments)[0][0] !== 1;
  })(1,2)

  if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;

  // use native browser JS 1.6 implementation if available
  if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
  if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
})();/** section: DOM, related to: Element
 *  $p(id) -> Element
 *  $p(id...) -> [Element...]
 *    - id (String | Element): A DOM node or a string that references a node's
 *      ID.
 *
 *  If provided with a string, returns the element in the document with
 *  matching ID; otherwise returns the passed element.
 *
 *  Takes in an arbitrary number of arguments. Returns one [[Element]] if
 *  given one argument; otherwise returns an [[Array]] of [[Element]]s.
 *
 *  All elements returned by the function are "extended" with [[Element]]
 *  instance methods.
 *
 *  ##### More Information
 *
 *  The [[$]] function is the cornerstone of Prototype. Not only does it
 *  provide a handy alias for `document.getElementById`, it also lets you pass
 *  indifferently IDs (strings) or DOM node references to your functions:
 *  
 *      function foo(element) {
 *          element = $p(element);
 *          //  rest of the function...
 *      }
 *  
 *  Code written this way is flexible — you can pass it the ID of the element
 *  or the element itself without any type sniffing.
 *  
 *  Invoking it with only one argument returns the [[Element]], while invoking it
 *  with multiple arguments returns an [[Array]] of [[Element]]s (and this
 *  works recursively: if you're twisted, you could pass it an array
 *  containing some arrays, and so forth). As this is dependent on
 *  `getElementById`, [W3C specs](http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-getElBId)
 *  apply: nonexistent IDs will yield `null` and IDs present multiple times in
 *  the DOM will yield erratic results. *If you're assigning the same ID to
 *  multiple elements, you're doing it wrong!*
 *  
 *  The function also *extends every returned element* with [[Element.extend]]
 *  so you can use Prototype's DOM extensions on it. In the following code,
 *  the two lines are equivalent. However, the second one feels significantly
 *  more object-oriented:
 *  
 *      // Note quite OOP-like...
 *      Element.hide('itemId');
 *      // A cleaner feel, thanks to guaranted extension
 *      $p('itemId').hide();
 *  
 *  However, when using iterators, leveraging the [[$]] function makes for
 *  more elegant, more concise, and also more efficient code:
 *  
 *      ['item1', 'item2', 'item3'].each(Element.hide);
 *      // The better way:
 *      $p('item1', 'item2', 'item3').invoke('hide');
 *  
 *  See [How Prototype extends the DOM](http://prototypejs.org/learn/extensions)
 *  for more info.
**/

function $p(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (Object.isString(element))
    element = document.getElementById(element);
  return Element.extend(element);
}

if (Prototype.BrowserFeatures.XPath) {
  document._getElementsByXPath = function(expression, parentElement) {
    var results = [];
    var query = document.evaluate(expression, $p(parentElement) || document,
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = 0, length = query.snapshotLength; i < length; i++)
      results.push(Element.extend(query.snapshotItem(i)));
    return results;
  };
}

/*--------------------------------------------------------------------------*/

if (!Node) var Node = { };

if (!Node.ELEMENT_NODE) {
  // DOM level 2 ECMAScript Language Binding
  Object.extend(Node, {
    ELEMENT_NODE: 1,
    ATTRIBUTE_NODE: 2,
    TEXT_NODE: 3,
    CDATA_SECTION_NODE: 4,
    ENTITY_REFERENCE_NODE: 5,
    ENTITY_NODE: 6,
    PROCESSING_INSTRUCTION_NODE: 7,
    COMMENT_NODE: 8,
    DOCUMENT_NODE: 9,
    DOCUMENT_TYPE_NODE: 10,
    DOCUMENT_FRAGMENT_NODE: 11,
    NOTATION_NODE: 12
  });
}

/** section: DOM
 *  class Element
 *
 *  The [[Element]] object provides a variety of powerful DOM methods for
 *  interacting with DOM elements&nbsp;&mdash; creating them, updating them,
 *  traversing them, etc. You can access these either as methods of [[Element]]
 *  itself, passing in the element to work with as the first argument, or as
 *  methods on extended element *instances*:
 *
 *      // Using Element:
 *      Element.addClassName('target', 'highlighted');
 *
 *      // Using an extended element instance:
 *      $p('target').addClassName('highlighted');
 *
 *  [[Element]] is also a constructor for building element instances from scratch,
 *  see [`new Element`](#new-constructor) for details.
 *
 *  Most [[Element]] methods return the element instance, so that you can chain
 *  them easily:
 *
 *      $p('message').addClassName('read').update('I read this message!');
 *
 *  ##### More Information
 *
 *  For more information about extended elements, check out ["How Prototype
 *  extends the DOM"](http://prototypejs.org/learn/extensions), which will walk
 *  you through the inner workings of Prototype's DOM extension mechanism.
**/

/**
 *  new Element(tagName[, attributes])
 *  - tagName (String): The name of the HTML element to create.
 *  - attributes (Object): An optional group of attribute/value pairs to set on
 *    the element.
 *
 *  Creates an HTML element with `tagName` as the tag name, optionally with the
 *  given attributes. This can be markedly more concise than working directly
 *  with the DOM methods, and takes advantage of Prototype's workarounds for
 *  various browser issues with certain attributes:
 *
 *  ##### Example
 *
 *      // The old way:
 *      var a = document.createElement('a');
 *      a.setAttribute('class', 'foo');
 *      a.setAttribute('href', '/foo.html');
 *      a.appendChild(document.createTextNode("Next page"));
 *
 *      // The new way:
 *      var a = new Element('a', {'class': 'foo', href: '/foo.html'}).update("Next page");
**/

(function(global) {  
  // For performance reasons, we create new elements by cloning a "blank"
  // version of a given element. But sometimes this causes problems. Skip
  // the cache if:
  //   (a) We're creating a SELECT element (troublesome in IE6);
  //   (b) We're setting the `type` attribute on an INPUT element
  //       (troublesome in IE9).
  function shouldUseCache(tagName, attributes) {
    if (tagName === 'select') return false;
    if ('type' in attributes) return false;
    return true;
  }
  
  var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){
    try {
      var el = document.createElement('<input name="x">');
      return el.tagName.toLowerCase() === 'input' && el.name === 'x';
    } 
    catch(err) {
      return false;
    }
  })();

  var element = global.Element;
      
  global.Element = function(tagName, attributes) {
    attributes = attributes || { };
    tagName = tagName.toLowerCase();
    var cache = Element.cache;
    
    if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {
      tagName = '<' + tagName + ' name="' + attributes.name + '">';
      delete attributes.name;      
      return Element.writeAttribute(document.createElement(tagName), attributes);
    }
    
    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
    
    var node = shouldUseCache(tagName, attributes) ? 
     cache[tagName].cloneNode(false) : document.createElement(tagName);
    
    return Element.writeAttribute(node, attributes);
  };
  
  Object.extend(global.Element, element || { });
  if (element) global.Element.prototype = element.prototype;
  
})(this);

Element.idCounter = 1;
Element.cache = { };

// Performs cleanup on an element before it is removed from the page.
// See `Element#purge`.
Element._purgeElement = function(element) {
  var uid = element._prototypeUID;
  if (uid) {
    // Must go first because it relies on Element.Storage.
    Element.stopObserving(element);
    element._prototypeUID = void 0;
    delete Element.Storage[uid];
  }
}

/**
 *  mixin Element.Methods
 *
 *  [[Element.Methods]] is a mixin for DOM elements. The methods of this object 
 *  are accessed through the [[$]] utility or through the [[Element]] object and
 *  shouldn't be accessed directly.
 *  
 *  ##### Examples
 *  
 *  Hide the element 
 *  
 *      $p(element).hide(); 
 *      
 *  Return an [[Enumerable]] of all descendant nodes of the element with the id
 *  "article"
 *  
 *      $p('articles').descendants();
**/
Element.Methods = {
  /**
   *  Element.visible(@element) -> Boolean
   *
   *  Tells whether `element` is visible (i.e., whether its inline `display`
   *  CSS property is set to `none`.
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <div id="visible"></div>
   *      <div id="hidden" style="display: none;"></div>
   *
   *  And the associated JavaScript:
   *
   *      $p('visible').visible();
   *      // -> true
   *      
   *      $p('hidden').visible();
   *      // -> false
   *  
   *  ##### Notes
   *  
   *  Styles applied via a CSS stylesheet are _not_ taken into consideration.
   *  Note that this is not a Prototype limitation, it is a CSS limitation.
   *  
   *      language: html
   *      <style>
   *        #hidden-by-css {
   *          display: none;
   *        }
   *      </style>
   *      
   *      [...]
   *      
   *      <div id="hidden-by-css"></div>
   *
   *  And the associated JavaScript:
   *
   *      $p('hidden-by-css').visible();
   *      // -> true
  **/
  visible: function(element) {
    return $p(element).style.display != 'none';
  },

  /**
   *  Element.toggle(@element) -> Element
   *
   *  Toggles the visibility of `element`. Returns `element`.
   *  
   *  ##### Examples
   *  
   *      <div id="welcome-message"></div>
   *      <div id="error-message" style="display:none;"></div>
   *  
   *      $p('welcome-message').toggle();
   *      // -> Element (and hides div#welcome-message)
   *      
   *      $p('error-message').toggle();
   *      // -> Element (and displays div#error-message)
   *  
   *  Toggle multiple elements using [[Enumerable#each]]:
   *  
   *      ['error-message', 'welcome-message'].each(Element.toggle);
   *      // -> ['error-message', 'welcome-message'] 
   *  
   *  Toggle multiple elements using [[Enumerable#invoke]]:
   *  
   *      $p('error-message', 'welcome-message').invoke('toggle');
   *      // -> [Element, Element]
   *
   *  ##### Notes
   *  
   *  [[Element.toggle]] _cannot_ display elements hidden via CSS stylesheets.
   *  Note that this is not a Prototype limitation but a consequence of how the
   *  CSS `display` property works.
   *  
   *      <style>
   *        #hidden-by-css {
   *          display: none;
   *        }
   *      </style>
   *      
   *      [...]
   *      
   *      <div id="hidden-by-css"></div>
   *  
   *      $p('hidden-by-css').toggle(); // WONT' WORK!
   *      // -> Element (div#hidden-by-css is still hidden!)
  **/
  toggle: function(element) {
    element = $p(element);
    Element[Element.visible(element) ? 'hide' : 'show'](element);
    return element;
  },

  /**
   *  Element.hide(@element) -> Element
   *
   *  Sets `display: none` on `element`. Returns `element`.
   *  
   *  ##### Examples
   *
   *  Hide a single element:
   *  
   *      <div id="error-message"></div>
   *  
   *      $p('error-message').hide();
   *      // -> Element (and hides div#error-message)
   *
   *  Hide multiple elements using [[Enumerable#each]]:
   *  
   *      ['content', 'navigation', 'footer'].each(Element.hide);
   *      // -> ['content', 'navigation', 'footer'] 
   *  
   *  Hide multiple elements using [[Enumerable#invoke]]:
   *  
   *      $p('content', 'navigation', 'footer').invoke('hide');
   *      // -> [Element, Element, Element]
  **/
  hide: function(element) {
    element = $p(element);
    element.style.display = 'none';
    return element;
  },

  /**
   *  Element.show(@element) -> Element
   *
   *  Removes `display: none` on `element`. Returns `element`.
   *  
   *  ##### Examples
   *
   *  Show a single element:
   *  
   *      <div id="error-message" style="display:none;"></div>
   *  
   *      $p('error-message').show();
   *      // -> Element (and displays div#error-message)
   *  
   *  Show multiple elements using [[Enumerable#each]]:
   *  
   *      ['content', 'navigation', 'footer'].each(Element.show);
   *      // -> ['content', 'navigation', 'footer'] 
   *  
   *  Show multiple elements using [[Enumerable#invoke]]:
   *  
   *      $p('content', 'navigation', 'footer').invoke('show');
   *      // -> [Element, Element, Element]
   *  
   *  ##### Notes
   *  
   *  [[Element.show]] _cannot_ display elements hidden via CSS stylesheets.
   *  Note that this is not a Prototype limitation but a consequence of how the
   *  CSS `display` property works.
   *  
   *      <style>
   *        #hidden-by-css {
   *          display: none;
   *        }
   *      </style>
   *      
   *      [...]
   *      
   *      <div id="hidden-by-css"></div>
   *  
   *      $p('hidden-by-css').show(); // DOES NOT WORK!
   *      // -> Element (div#error-message is still hidden!)
  **/
  show: function(element) {
    element = $p(element);
    element.style.display = '';
    return element;
  },

  /**
   *  Element.remove(@element) -> Element
   *
   *  Completely removes `element` from the document and returns it.
   *
   *  If you would rather just hide the element and keep it around for further
   *  use, try [[Element.hide]] instead.
   *  
   *  ##### Examples
   *  
   *      language: html
   *      // Before:
   *      <ul>
   *        <li id="golden-delicious">Golden Delicious</li>
   *        <li id="mutsu">Mutsu</li>
   *        <li id="mcintosh">McIntosh</li>
   *        <li id="ida-red">Ida Red</li>
   *      </ul>
   *
   *  And the associated JavaScript:
   *
   *      $p('mutsu').remove();
   *      // -> Element (and removes li#mutsu)
   *  
   *  The resulting HTML:
   *
   *      language: html
   *      <ul>
   *        <li id="golden-delicious">Golden Delicious</li>
   *        <li id="mcintosh">McIntosh</li>
   *        <li id="ida-red">Ida Red</li>
   *      </ul>
  **/
  remove: function(element) {
    element = $p(element);
    element.parentNode.removeChild(element);
    return element;
  },

  /**
   *  Element.update(@element[, newContent]) -> Element
   *
   *  Replaces _the content_ of `element` with the `newContent` argument and
   *  returns `element`.
   *
   *  `newContent` may be in any of these forms:
   *  - [[String]]: A string of HTML to be parsed and rendered
   *  - [[Element]]: An Element instance to insert
   *  - ...any object with a `toElement` method: The method is called and the resulting element used
   *  - ...any object with a `toHTML` method: The method is called and the resulting HTML string
   *    is parsed and rendered
   *
   *  If `newContent` is omitted, the element's content is blanked out (i.e.,
   *  replaced with an empty string).
   *
   *  If `newContent` is a string and contains one or more inline `<script>` 
   *  tags, the scripts are scheduled to be evaluated after a very brief pause
   *  (using [[Function#defer]]) to allow the browser to finish updating the 
   *  DOM. Note that the scripts are evaluated in the scope of 
   *  [[String#evalScripts]], not in the global scope, which has important
   *  ramifications for your `var`s and `function`s.
   *  See [[String#evalScripts]] for details.
   *
   *  Note that this method allows seamless content update of table related 
   *  elements in Internet Explorer 6 and beyond.
   *  
   *  Any nodes replaced with `Element.update` will first have event
   *  listeners unregistered and storage keys removed. This frees up memory
   *  and prevents leaks in certain versions of Internet Explorer. (See
   *  [[Element.purge]]).
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <div id="fruits">carrot, eggplant and cucumber</div>
   *  
   *  Passing a regular string:
   *  
   *      $p('fruits').update('kiwi, banana and apple');
   *      // -> Element
   *      $p('fruits').innerHTML;
   *      // -> 'kiwi, banana and apple'
   *  
   *  Clearing the element's content:
   *  
   *      $p('fruits').update();
   *      // -> Element
   *      $p('fruits').innerHTML;
   *      // -> '' (an empty string)
   *  
   *  And now inserting an HTML snippet:
   *  
   *      $p('fruits').update('<p>Kiwi, banana <em>and</em> apple.</p>');
   *      // -> Element
   *      $p('fruits').innerHTML;
   *      // -> '<p>Kiwi, banana <em>and</em> apple.</p>'
   *  
   *  ... with a `<script>` tag thrown in:
   *  
   *      $p('fruits').update('<p>Kiwi, banana <em>and</em> apple.</p><script>alert("updated!")</script>');
   *      // -> Element (and prints "updated!" in an alert dialog).
   *      $p('fruits').innerHTML;
   *      // -> '<p>Kiwi, banana <em>and</em> apple.</p>'
   *  
   *  Relying on the `toString()` method:
   *  
   *      $p('fruits').update(123);
   *      // -> Element
   *      $p('fruits').innerHTML;
   *      // -> '123'
   *  
   *  Finally, you can do some pretty funky stuff by defining your own
   *  `toString()` method on your custom objects:
   *  
   *      var Fruit = Class.create({
   *        initialize: function(fruit){
   *          this.fruit = fruit;
   *        },
   *        toString: function(){
   *          return 'I am a fruit and my name is "' + this.fruit + '".'; 
   *        }
   *      });
   *      var apple = new Fruit('apple');
   *      
   *      $p('fruits').update(apple);
   *      $p('fruits').innerHTML;
   *      // -> 'I am a fruit and my name is "apple".'
  **/
  update: (function(){

    // see: http://support.microsoft.com/kb/276228
    var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
      var el = document.createElement("select"),
          isBuggy = true;
      el.innerHTML = "<option value=\"test\">test</option>";
      if (el.options && el.options[0]) {
        isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
      }
      el = null;
      return isBuggy;
    })();

    // see: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
    var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
      try {
        var el = document.createElement("table");
        if (el && el.tBodies) {
          el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
          var isBuggy = typeof el.tBodies[0] == "undefined";
          el = null;
          return isBuggy;
        }
      } catch (e) {
        return true;
      }
    })();
    
    var LINK_ELEMENT_INNERHTML_BUGGY = (function() {
      try {
        var el = document.createElement('div');
        el.innerHTML = "<link>";
        var isBuggy = (el.childNodes.length === 0);
        el = null;
        return isBuggy;
      } catch(e) {
        return true;
      }
    })();
    
    var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
     TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;    

    var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
      var s = document.createElement("script"),
          isBuggy = false;
      try {
        s.appendChild(document.createTextNode(""));
        isBuggy = !s.firstChild ||
          s.firstChild && s.firstChild.nodeType !== 3;
      } catch (e) {
        isBuggy = true;
      }
      s = null;
      return isBuggy;
    })();
    

    function update(element, content) {
      element = $p(element);
      var purgeElement = Element._purgeElement;
      
      // Purge the element's existing contents of all storage keys and
      // event listeners, since said content will be replaced no matter
      // what.
      var descendants = element.getElementsByTagName('*'),
       i = descendants.length;
      while (i--) purgeElement(descendants[i]);
      
      if (content && content.toElement)
        content = content.toElement();

      if (Object.isElement(content))
        return element.update().insert(content);

      content = Object.toHTML(content);

      var tagName = element.tagName.toUpperCase();

      if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
        // scripts are not evaluated when updating SCRIPT element
        element.text = content;
        return element;
      }

      if (ANY_INNERHTML_BUGGY) {
        if (tagName in Element._insertionTranslations.tags) {
          while (element.firstChild) {
            element.removeChild(element.firstChild);
          }
          Element._getContentFromAnonymousElement(tagName, content.stripScripts())
            .each(function(node) {
              element.appendChild(node)
            });
        } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
          // IE barfs when inserting a string that beings with a LINK
          // element. The workaround is to add any content to the beginning
          // of the string; we'll be inserting a text node (see
          // Element._getContentFromAnonymousElement below).
          while (element.firstChild) {
            element.removeChild(element.firstChild);
          }
          var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true);
          nodes.each(function(node) { element.appendChild(node) });          
        }
        else {
          element.innerHTML = content.stripScripts();
        }
      }
      else {
        element.innerHTML = content.stripScripts();
      }

      content.evalScripts.bind(content).defer();
      return element;
    }

    return update;
  })(),

  /**
   *  Element.replace(@element[, newContent]) -> Element
   *
   *  Replaces `element` _itself_ with `newContent` and returns `element`.
   *
   *  Keep in mind that this method returns the element that has just been
   *  removed &mdash; not the element that took its place.
   *
   *  `newContent` can be either plain text, an HTML snippet or any JavaScript
   *  object which has a `toString()` method.
   *  
   *  If `newContent` contains any `<script>` tags, these will be evaluated
   *  after `element` has been replaced ([[Element.replace]] internally calls
   *  [[String#evalScripts]]).
   *  
   *  Note that if no argument is provided, [[Element.replace]] will simply
   *  clear `element` of its content. However, using [[Element.remove]] to do so
   *  is both faster and more standard compliant.
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <div id="food">
   *        <div id="fruits">
   *          <p id="first">Kiwi, banana <em>and</em> apple.</p>
   *        </div>
   *      </div>
   *  
   *  Passing an HTML snippet:
   *  
   *      $p('first').replace('<ul id="favorite"><li>kiwi</li><li>banana</li><li>apple</li></ul>');
   *      // -> Element (p#first)
   *      
   *      $p('fruits').innerHTML;
   *      // -> '<ul id="favorite"><li>kiwi</li><li>banana</li><li>apple</li></ul>'
   *  
   *  Again, with a `<script>` tag thrown in:
   *  
   *      $p('favorite').replace('<p id="still-first">Melon, oranges <em>and</em> grapes.</p><script>alert("removed!")</script>');
   *      // -> Element (ul#favorite) and prints "removed!" in an alert dialog.
   *      
   *      $p('fruits').innerHTML;
   *      // -> '<p id="still-first">Melon, oranges <em>and</em> grapes.</p>'
   *  
   *  With plain text:
   *  
   *      $p('still-first').replace('Melon, oranges and grapes.');
   *      // -> Element (p#still-first)
   *
   *      $p('fruits').innerHTML;
   *      // -> 'Melon, oranges and grapes.'
   *  
   *  Finally, relying on the `toString()` method:
   *  
   *      $p('fruits').replace(123);
   *      // -> Element
   *      
   *      $p('food').innerHTML;
   *      // -> '123'
   *
   *  ##### Warning
   *
   *  Using [[Element.replace]] as an instance method (e.g.,
   *  `$('foo').replace('<p>Bar</p>')`) causes errors in Opera 9 when used on
   *  `input` elements. The `replace` property is reserved on `input` elements
   *  as part of [Web Forms 2](http://www.whatwg.org/specs/web-forms/current-work/).
   *  As a workaround, use the generic version instead
   *  (`Element.replace('foo', '<p>Bar</p>')`).
   *  
  **/
  replace: function(element, content) {
    element = $p(element);
    if (content && content.toElement) content = content.toElement();
    else if (!Object.isElement(content)) {
      content = Object.toHTML(content);
      var range = element.ownerDocument.createRange();
      range.selectNode(element);
      content.evalScripts.bind(content).defer();
      content = range.createContextualFragment(content.stripScripts());
    }
    element.parentNode.replaceChild(content, element);
    return element;
  },

  /**
   *  Element.insert(@element, content) -> Element
   *  - content (String | Element | Object): The content to insert.
   *
   *  Inserts content `above`, `below`, at the `top`, and/or at the `bottom` of
   *  the given element, depending on the option(s) given.
   *
   *  `insert` accepts content in any of these forms:
   *  - [[String]]: A string of HTML to be parsed and rendered
   *  - [[Element]]: An Element instance to insert
   *  - ...any object with a `toElement` method: The method is called and the resulting element used
   *  - ...any object with a `toHTML` method: The method is called and the resulting HTML string
   *    is parsed and rendered
   *
   *  The `content` argument can be the content to insert, in which case the
   *  implied insertion point is `bottom`, or an object that specifies one or
   *  more insertion points (e.g., `{ bottom: "foo", top: "bar" }`).
   *
   *  Accepted insertion points are:
   *  - `before` (as `element`'s previous sibling)
   *  - `after` (as `element's` next sibling)
   *  - `top` (as `element`'s first child)
   *  - `bottom` (as `element`'s last child)
   *
   *  Note that if the inserted HTML contains any `<script>` tag, these will be
   *  automatically evaluated after the insertion (`insert` internally calls
   *  [[String.evalScripts]] when inserting HTML).
   *
   *  <h5>Examples</h5>
   *
   *  Insert the given HTML at the bottom of the element (using the default):
   *
   *      $p('myelement').insert("<p>HTML to append</p>");
   *
   *      $p('myelement').insert({
   *        top: new Element('img', {src: 'logo.png'})
   *      });
   *
   *  Put `hr`s `before` and `after` the element:
   *
   *      $p('myelement').insert({
   *        before: "<hr>",
   *        after: "<hr>"
   *      });
  **/
  insert: function(element, insertions) {
    element = $p(element);

    if (Object.isString(insertions) || Object.isNumber(insertions) ||
        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
          insertions = {bottom:insertions};

    var content, insert, tagName, childNodes;

    for (var position in insertions) {
      content  = insertions[position];
      position = position.toLowerCase();
      insert = Element._insertionTranslations[position];

      if (content && content.toElement) content = content.toElement();
      if (Object.isElement(content)) {
        insert(element, content);
        continue;
      }

      content = Object.toHTML(content);

      tagName = ((position == 'before' || position == 'after')
        ? element.parentNode : element).tagName.toUpperCase();

      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());

      if (position == 'top' || position == 'after') childNodes.reverse();
      childNodes.each(insert.curry(element));

      content.evalScripts.bind(content).defer();
    }

    return element;
  },

  /**
   *  Element.wrap(@element, wrapper[, attributes]) -> Element
   *  - wrapper (Element | String): An element to wrap `element` inside, or
   *    else a string representing the tag name of an element to be created.
   *  - attributes (Object): A set of attributes to apply to the wrapper
   *    element. Refer to the [[Element]] constructor for usage.
   *
   *  Wraps an element inside another, then returns the wrapper.
   *  
   *  If the given element exists on the page, [[Element.wrap]] will wrap it in
   *  place — its position will remain the same.
   *  
   *  The `wrapper` argument can be _either_ an existing [[Element]] _or_ a
   *  string representing the tag name of an element to be created. The optional
   *  `attributes` argument can contain a list of attribute/value pairs that
   *  will be set on the wrapper using [[Element.writeAttribute]].
   *  
   *  ##### Examples
   *  
   *  Original HTML:
   *  
   *      language: html
   *      <table id="data">
   *        <tr>
   *          <th>Foo</th>
   *          <th>Bar</th>
   *        </tr>
   *        <tr>
   *          <td>1</td>
   *          <td>2</td>
   *        </tr>
   *      </table>
   *  
   *  JavaScript:
   *  
   *      // approach 1:
   *      var div = new Element('div', { 'class': 'table-wrapper' });
   *      $p('data').wrap(div);
   *      
   *      // approach 2:
   *      $p('data').wrap('div', { 'class': 'table-wrapper' });
   *      
   *      // Both examples are equivalent &mdash; they return the DIV.
   *  
   *  Resulting HTML:
   *  
   *      language: html
   *      <div class="table-wrapper">
   *        <table id="data">
   *          <tr>
   *            <th>Foo</th>
   *            <th>Bar</th>
   *          </tr>
   *          <tr>
   *            <td>1</td>
   *            <td>2</td>
   *          </tr>
   *        </table>
   *      </div> 
   *  
   *  ##### Warning
   *
   *  Using [[Element.wrap]] as an instance method (e.g., `$('foo').wrap('p')`)
   *  causes errors in Internet Explorer when used on `textarea` elements. The
   *  `wrap` property is reserved on `textarea`'s as a proprietary extension to
   *  HTML. As a workaround, use the generic version instead
   *  (`Element.wrap('foo', 'p')`).
  **/
  wrap: function(element, wrapper, attributes) {
    element = $p(element);
    if (Object.isElement(wrapper))
      $p(wrapper).writeAttribute(attributes || { });
    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
    else wrapper = new Element('div', wrapper);
    if (element.parentNode)
      element.parentNode.replaceChild(wrapper, element);
    wrapper.appendChild(element);
    return wrapper;
  },

  /**
   *  Element.inspect(@element) -> String
   *
   *  Returns the debug-oriented string representation of `element`.
   *
   *  For more information on `inspect` methods, see [[Object.inspect]].
   *  
   *      language: html
   *      <ul>
   *        <li id="golden-delicious">Golden Delicious</li>
   *        <li id="mutsu" class="yummy apple">Mutsu</li>
   *        <li id="mcintosh" class="yummy">McIntosh</li>
   *        <li></li>
   *      </ul>
   *
   *  And the associated JavaScript:
   *
   *      $p('golden-delicious').inspect();
   *      // -> '<li id="golden-delicious">'
   *      
   *      $p('mutsu').inspect();
   *      // -> '<li id="mutsu" class="yummy apple">'
   *      
   *      $p('mutsu').next().inspect();
   *      // -> '<li>'
  **/
  inspect: function(element) {
    element = $p(element);
    var result = '<' + element.tagName.toLowerCase();
    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
      var property = pair.first(), 
          attribute = pair.last(),
          value = (element[property] || '').toString();
      if (value) result += ' ' + attribute + '=' + value.inspect(true);
    });
    return result + '>';
  },
  /**
   *  Element.ancestors(@element) -> [Element...]
   *
   *  Collects all of `element`'s ancestor elements and returns them as an
   *  array of extended elements.
   *
   *  The returned array's first element is `element`'s direct ancestor (its
   *  `parentNode`), the second one is its grandparent, and so on until the
   *  `<html>` element is reached. `<html>` will always be the last member of
   *  the array. Calling `ancestors` on the `<html>` element will return an
   *  empty array.
   *
   *  ##### Example
   *
   *  Assuming:
   *
   *      language: html
   *      <html>
   *      [...]
   *        <body>
   *          <div id="father">
   *            <div id="kid">
   *            </div>
   *          </div>
   *        </body>
   *      </html>
   *
   *  Then:
   *
   *      $p('kid').ancestors();
   *      // -> [div#father, body, html]
  **/
  ancestors: function(element) {
    return Element.recursivelyCollect(element, 'parentNode');
  },

  /**
   *  Element.descendants(@element) -> [Element...]
   *
   *  Collects all of the element's descendants (its children, their children,
   *  etc.) and returns them as an array of extended elements. As with all of
   *  Prototype's DOM traversal methods, only [[Element]]s are returned, other
   *  nodes (text nodes, etc.) are skipped.
  **/
  descendants: function(element) {
    return Element.select(element, "*");
  },

  /**
   *  Element.firstDescendant(@element) -> Element
   *
   *  Returns the first child that is an element.
   *
   *  This is opposed to the `firstChild` DOM property, which will return
   *  any node, including text nodes and comment nodes.
   *
   *  ##### Examples
   *  
   *      language: html
   *      <div id="australopithecus">
   *        <div id="homo-erectus"><!-- Latin is super -->
   *          <div id="homo-neanderthalensis"></div>
   *          <div id="homo-sapiens"></div>
   *        </div>
   *      </div>
   *
   *  Then:
   *
   *      $p('australopithecus').firstDescendant();
   *      // -> div#homo-herectus
   *      
   *      // the DOM property returns any first node
   *      $p('homo-herectus').firstChild;
   *      // -> comment node "Latin is super"
   *      
   *      // this is what we want!
   *      $p('homo-herectus').firstDescendant();
   *      // -> div#homo-neanderthalensis
  **/
  firstDescendant: function(element) {
    element = $p(element).firstChild;
    while (element && element.nodeType != 1) element = element.nextSibling;
    return $p(element);
  },

  /** deprecated, alias of: Element.childElements
   *  Element.immediateDescendants(@element) -> [Element...]
   *
   *  **This method is deprecated, please see [[Element.childElements]]**.
  **/
  immediateDescendants: function(element) {
    var results = [], child = $p(element).firstChild;
    while (child) {
      if (child.nodeType === 1) {
        results.push(Element.extend(child));
      }
      child = child.nextSibling;
    }
    return results;
  },

  /**
   *  Element.previousSiblings(@element) -> [Element...]
   *
   *  Collects all of `element`'s previous siblings and returns them as an
   *  [[Array]] of elements.
   *  
   *  Two elements are siblings if they have the same parent. So for example,
   *  the `<head>` and `<body>` elements are siblings (their parent is the
   *  `<html>` element). Previous-siblings are simply the ones which precede
   *  `element` in the document.
   *  
   *  The returned [[Array]] reflects the siblings _inversed_ order in the
   *  document (e.g. an index of 0 refers to the lowest sibling i.e., the one
   *  closest to `element`).
   *  
   *  Note that all of Prototype's DOM traversal methods ignore text nodes and
   *  return element nodes only.
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <ul>
   *        <li id="golden-delicious">Golden Delicious</li>
   *        <li id="mutsu">Mutsu</li>
   *        <li id="mcintosh">McIntosh</li>
   *        <li id="ida-red">Ida Red</li>
   *      </ul>
   *
   *  Then:
   *
   *      $p('mcintosh').previousSiblings();
   *      // -> [li#mutsu, li#golden-delicious]
   *      
   *      $p('golden-delicious').previousSiblings();
   *      // -> []
  **/
  previousSiblings: function(element, maximumLength) {
    return Element.recursivelyCollect(element, 'previousSibling');
  },

  /**
   *  Element.nextSiblings(@element) -> [Element...]
   *
   *  Collects all of `element`'s next siblings and returns them as an [[Array]]
   *  of elements.
   *  
   *  Two elements are siblings if they have the same parent. So for example,
   *  the `head` and `body` elements are siblings (their parent is the `html`
   *  element). Next-siblings are simply the ones which follow `element` in the
   *  document.
   *  
   *  The returned [[Array]] reflects the siblings order in the document
   *  (e.g. an index of 0 refers to the sibling right below `element`).
   *  
   *  Note that all of Prototype's DOM traversal methods ignore text nodes and
   *  return element nodes only.
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <ul>
   *        <li id="golden-delicious">Golden Delicious</li>
   *        <li id="mutsu">Mutsu</li>
   *        <li id="mcintosh">McIntosh</li>
   *        <li id="ida-red">Ida Red</li>
   *      </ul>
   *
   *  Then:
   *
   *      $p('mutsu').nextSiblings();
   *      // -> [li#mcintosh, li#ida-red]
   *      
   *      $p('ida-red').nextSiblings();
   *      // -> []
  **/
  nextSiblings: function(element) {
    return Element.recursivelyCollect(element, 'nextSibling');
  },

  /**
   *  Element.siblings(@element) -> [Element...]
   *  Collects all of element's siblings and returns them as an [[Array]] of
   *  elements.
   *
   *  Two elements are siblings if they have the same parent. So for example,
   *  the `head` and `body` elements are siblings (their parent is the `html`
   *  element).
   *  
   *  The returned [[Array]] reflects the siblings' order in the document (e.g.
   *  an index of 0 refers to `element`'s topmost sibling).
   *  
   *  Note that all of Prototype's DOM traversal methods ignore text nodes and
   *  return element nodes only.
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <ul>
   *        <li id="golden-delicious">Golden Delicious</li>
   *        <li id="mutsu">Mutsu</li>
   *        <li id="mcintosh">McIntosh</li>
   *        <li id="ida-red">Ida Red</li>
   *      </ul>
   *
   *  Then:
   *
   *      $p('mutsu').siblings();
   *      // -> [li#golden-delicious, li#mcintosh, li#ida-red]
  **/
  siblings: function(element) {
    element = $p(element);
    return Element.previousSiblings(element).reverse()
      .concat(Element.nextSiblings(element));
  },
  /**
   *  Element.down(@element[, expression[, index = 0]]) -> Element
   *  Element.down(@element[, index = 0]) -> Element
   *  - expression (String): A CSS selector.
   *
   *  Returns `element`'s first descendant (or the Nth descendant, if `index`
   *  is specified) that matches `expression`. If no `expression` is
   *  provided, all descendants are considered. If no descendant matches these
   *  criteria, `undefined` is returned.
   *
   *  ##### More information
   *
   *  The [[Element.down]] method is part of Prototype's ultimate DOM traversal
   *  toolkit (check out [[Element.up]], [[Element.next]] and
   *  [[Element.previous]] for some more Prototypish niceness). It allows
   *  precise index-based and/or CSS rule-based selection of any of the 
   *  element's **descendants**.
   *  
   *  As it totally ignores text nodes (it only returns elements), you don't
   *  have to worry about whitespace nodes.
   *  
   *  And as an added bonus, all elements returned are already extended
   *  (see [[Element.extend]]) allowing chaining:
   *  
   *      $p(element).down(1).next('li', 2).hide();
   *  
   *  Walking the DOM has never been that easy!
   *  
   *  ##### Arguments
   *  
   *  If no arguments are passed, `element`'s first descendant is returned (this
   *  is similar to calling `firstChild` except [[Element.down]] returns an
   *  extended element.
   *  
   *  If `index` is defined, `element`'s corresponding descendant is returned.
   *  (This is equivalent to selecting an element from the array of elements
   *  returned by the method [[Element.descendants]].) Note that the first
   *  element has an index of 0.
   *  
   *  If `expression` is defined, [[Element.down]] will return the first
   *  descendant that matches it. This is a great way to grab the first item in
   *  a list for example (just pass in 'li' as the method's first argument).
   *  
   *  If both `expression` and `index` are defined, [[Element.down]] will collect
   *  all the descendants matching the given CSS expression and will return the
   *  one at the specified index.
   *  
   *  **In all of the above cases, if no descendant is found,** `undefined`
   *  **will be returned.**
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <ul id="fruits">
   *        <li id="apples">
   *          <ul>
   *            <li id="golden-delicious">Golden Delicious</li>
   *            <li id="mutsu" class="yummy">Mutsu</li>
   *            <li id="mcintosh" class="yummy">McIntosh</li>
   *            <li id="ida-red">Ida Red</li>
   *          </ul>
   *        </li>
   *      </ul>
   *      
   *  Get the first descendant of "#fruites":
   *
   *      $p('fruits').down();
   *      // or:
   *      $p('fruits').down(0);
   *      // -> li#apples
   *
   *  Get the third descendant of "#fruits":
   *      
   *      $p('fruits').down(3);
   *      // -> li#golden-delicious
   *      
   *  Get the first descendant of "#apples" with the node name "li":
   *
   *      $p('apples').down('li');
   *      // -> li#golden-delicious
   *
   *  Get the first descendant of "#apples" with the node name "li" and the
   *  class name "yummy":
   *
   *      $p('apples').down('li.yummy');
   *      // -> li#mutsu
   *
   *  Get the second descendant of "#fruits" with the class name "yummy":
   *
   *      $p('fruits').down('.yummy', 1);
   *      // -> li#mcintosh
   *
   *  Try to get the ninety-ninth descendant of "#fruits":
   *
   *      $p('fruits').down(99);
   *      // -> undefined
  **/
  down: function(element, expression, index) {
    element = $p(element);
    if (arguments.length == 1) return Element.firstDescendant(element);
    return Object.isNumber(expression) ? Element.descendants(element)[expression] :
      Element.select(element, expression)[index || 0];
  },

  /**
   *  Element.previous(@element[, expression[, index = 0]]) -> Element
   *  Element.previous(@element[, index = 0]) -> Element
   *  - expression (String): A CSS selector.
   *
   *  Returns `element`'s first previous sibling (or the Nth, if `index`
   *  is specified) that matches `expression`. If no `expression` is
   *  provided, all previous siblings are considered. If none matches these
   *  criteria, `undefined` is returned.
   *
   *  ##### More information
   *
   *  The [[Element.previous]] method is part of Prototype's ultimate DOM
   *  traversal toolkit (check out [[Element.up]], [[Element.down]] and
   *  [[Element.next]] for some more Prototypish niceness). It allows precise
   *  index-based and/or CSS expression-based selection of any of `element`'s
   *  **previous siblings**. (Note that two elements are considered siblings if
   *  they have the same parent, so for example, the `head` and `body` elements
   *  are siblings&#8212;their parent is the `html` element.)
   *  
   *  As it totally ignores text nodes (it only returns elements), you don't
   *  have to worry about whitespace nodes.
   *  
   *  And as an added bonus, all elements returned are already extended (see 
   *  [[Element.extend]]) allowing chaining:
   *  
   *      $p(element).down('p').previous('ul', 2).hide();
   *  
   *  Walking the DOM has never been that easy!
   *  
   *  ##### Arguments
   *  
   *  If no arguments are passed, `element`'s previous sibling is returned
   *  (this is similar as calling `previousSibling` except [[Element.previous]]
   *  returns an already extended element).
   *  
   *  If `index` is defined, `element`'s corresponding previous sibling is
   *  returned. (This is equivalent to selecting an element from the array of
   *  elements returned by the method [[Element.previousSiblings]]). Note that
   *  the sibling _right above_ `element` has an index of 0.
   *  
   *  If `expression` is defined, [[Element.previous]] will return the `element`
   *  first previous sibling that matches it.
   *  
   *  If both `expression` and `index` are defined, [[Element.previous]] will
   *  collect all of `element`'s previous siblings matching the given CSS
   *  expression and will return the one at the specified index.
   *  
   *  **In all of the above cases, if no previous sibling is found,**
   *  `undefined` **will be returned.**
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <ul id="fruits">
   *        <li id="apples">
   *          <h3>Apples</h3>
   *          <ul id="list-of-apples">
   *            <li id="golden-delicious" class="yummy">Golden Delicious</li>
   *            <li id="mutsu" class="yummy">Mutsu</li>
   *            <li id="mcintosh">McIntosh</li>
   *            <li id="ida-red">Ida Red</li>
   *          </ul>
   *          <p id="saying">An apple a day keeps the doctor away.</p>  
   *        </li>
   *      </ul>
   *  
   *  Get the first previous sibling of "#saying":
   *  
   *      $p('saying').previous();
   *      // or:
   *      $p('saying').previous(0);
   *      // -> ul#list-of-apples
   *
   *  Get the second previous sibling of "#saying":
   *
   *      $p('saying').previous(1);
   *      // -> h3
   *
   *  Get the first previous sibling of "#saying" with node name "h3":
   *
   *      $p('saying').previous('h3');
   *      // -> h3
   *
   *  Get the first previous sibling of "#ida-red" with class name "yummy":
   *
   *      $p('ida-red').previous('.yummy');
   *      // -> li#mutsu
   *
   *  Get the second previous sibling of "#ida-red" with class name "yummy":
   *
   *      $p('ida-red').previous('.yummy', 1);
   *      // -> li#golden-delicious
   *
   *  Try to get the sixth previous sibling of "#ida-red":
   *      
   *      $p('ida-red').previous(5);
   *      // -> undefined
  **/
  previous: function(element, expression, index) {
    element = $p(element);
    if (Object.isNumber(expression)) index = expression, expression = false;
    if (!Object.isNumber(index)) index = 0;
    
    if (expression) {
      return Prototype.Selector.find(element.previousSiblings(), expression, index);
    } else {
      return element.recursivelyCollect("previousSibling", index + 1)[index];
    }
  },

  /**
   *  Element.next(@element[, expression[, index = 0]]) -> Element
   *  Element.next(@element[, index = 0]) -> Element
   *  - expression (String): A CSS selector.
   *
   *  Returns `element`'s first following sibling (or the Nth, if `index`
   *  is specified) that matches `expression`. If no `expression` is
   *  provided, all following siblings are considered. If none matches these
   *  criteria, `undefined` is returned.
   *
   *  ##### More information
   *
   *  The [[Element.next]] method is part of Prototype's ultimate DOM traversal
   *  toolkit (check out [[Element.up]], [[Element.down]] and
   *  [[Element.previous]] for some more Prototypish niceness). It allows
   *  precise index-based and/or CSS expression-based selection of any of
   *  `element`'s **following siblings**. (Note that two elements are considered
   *  siblings if they have the same parent, so for example, the `head` and
   *  `body` elements are siblings&#8212;their parent is the `html` element.)
   *  
   *  As it totally ignores text nodes (it only returns elements), you don't
   *  have to worry about whitespace nodes.
   *  
   *  And as an added bonus, all elements returned are already extended (see 
   *  [[Element.extend]]) allowing chaining:
   *  
   *      $p(element).down(1).next('li', 2).hide();
   *  
   *  Walking the DOM has never been that easy!
   *  
   *  ##### Arguments
   *  
   *  If no arguments are passed, `element`'s following sibling is returned
   *  (this is similar as calling `nextSibling` except [[Element.next]] returns an
   *  already extended element).
   *  
   *  If `index` is defined, `element`'s corresponding following sibling is
   *  returned. (This is equivalent to selecting an element from the array of
   *  elements returned by the method [[Element.nextSiblings]]). Note that the
   *  sibling _right below_ `element` has an index of 0.
   *  
   *  If `expression` is defined, [[Element.next]] will return the `element` first
   *  following sibling that matches it.
   *  
   *  If both `expression` and `index` are defined, [[Element.next]] will collect
   *  all of `element`'s following siblings matching the given CSS expression
   *  and will return the one at the specified index.
   *  
   *  **In all of the above cases, if no following sibling is found,**
   *  `undefined` **will be returned.**
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <ul id="fruits">
   *        <li id="apples">
   *          <h3 id="title">Apples</h3>
   *          <ul id="list-of-apples">
   *            <li id="golden-delicious">Golden Delicious</li>
   *            <li id="mutsu">Mutsu</li>
   *            <li id="mcintosh" class="yummy">McIntosh</li>
   *            <li id="ida-red" class="yummy">Ida Red</li>
   *          </ul>
   *          <p id="saying">An apple a day keeps the doctor away.</p>  
   *        </li>
   *      </ul>
   *
   *  Get the first sibling after "#title":
   *  
   *      $p('title').next();
   *      // or:
   *      $p('title').next(0);
   *      // -> ul#list-of-apples
   *
   *  Get the second sibling after "#title":
   *
   *      $p('title').next(1);
   *      // -> p#saying
   *
   *  Get the first sibling after "#title" with node name "p":
   *
   *      $p('title').next('p');
   *      // -> p#sayings
   *
   *  Get the first sibling after "#golden-delicious" with class name "yummy":
   *      
   *      $p('golden-delicious').next('.yummy');
   *      // -> li#mcintosh
   *
   *  Get the second sibling after "#golden-delicious" with class name "yummy":
   *
   *      $p('golden-delicious').next('.yummy', 1);
   *      // -> li#ida-red
   *
   *  Try to get the first sibling after "#ida-red":
   *
   *      $p('ida-red').next();
   *      // -> undefined   
  **/
  next: function(element, expression, index) {
    element = $p(element);
    if (Object.isNumber(expression)) index = expression, expression = false;
    if (!Object.isNumber(index)) index = 0;
    
    if (expression) {
      return Prototype.Selector.find(element.nextSiblings(), expression, index);
    } else {
      var maximumLength = Object.isNumber(index) ? index + 1 : 1;
      return element.recursivelyCollect("nextSibling", index + 1)[index];
    }
  },


  /**
   *  Element.select(@element, expression...) -> [Element...]
   *  - expression (String): A CSS selector.
   *
   *  Takes an arbitrary number of CSS selectors and returns an array of
   *  descendants of `element` that match any of them.
   *
   *  This method is very similar to [[$$]] but can be used within the context 
   *  of one element, rather than the whole document. The supported CSS syntax 
   *  is identical, so please refer to the [[$$]] docs for details.
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <ul id="fruits">
   *        <li id="apples">
   *          <h3 title="yummy!">Apples</h3>
   *          <ul id="list-of-apples">
   *            <li id="golden-delicious" title="yummy!" >Golden Delicious</li>
   *            <li id="mutsu" title="yummy!">Mutsu</li>
   *            <li id="mcintosh">McIntosh</li>
   *            <li id="ida-red">Ida Red</li>
   *          </ul>
   *          <p id="saying">An apple a day keeps the doctor away.</p>  
   *        </li>
   *      </ul>
   *
   *  Then:
   *
   *      $p('apples').select('[title="yummy!"]');
   *      // -> [h3, li#golden-delicious, li#mutsu]
   *      
   *      $p('apples').select( 'p#saying', 'li[title="yummy!"]');
   *      // -> [li#golden-delicious, li#mutsu,  p#saying]
   *      
   *      $p('apples').select('[title="disgusting!"]');
   *      // -> []
   *  
   *  ##### Tip
   *
   *  [[Element.select]] can be used as a pleasant alternative to the native
   *  method `getElementsByTagName`:
   *  
   *      var nodes  = $A(someUL.getElementsByTagName('li')).map(Element.extend);
   *      var nodes2 = someUL.select('li');
   *  
   *  In the first example, you must explicitly convert the result set to an
   *  [[Array]] (so that Prototype's [[Enumerable]] methods can be used) and
   *  must manually call [[Element.extend]] on each node (so that custom 
   *  instance methods can be used on the nodes). [[Element.select]] takes care 
   *  of both concerns on its own.
   *  
   *  If you're using 1.6 or above (and the performance optimizations therein), 
   *  the speed difference between these two examples is negligible.
  **/
  select: function(element) {
    element = $p(element);
    var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
    return Prototype.Selector.select(expressions, element);
  },

  /**
   *  Element.adjacent(@element, selector...) -> [Element...]
   *  - selector (String): A CSS selector.
   *
   *  Finds all siblings of the current element that match the given
   *  selector(s). If you provide multiple selectors, siblings matching *any*
   *  of the selectors are included. If a sibling matches multiple selectors,
   *  it is only included once. The order of the returned array is not defined.
   *
   *  ##### Example
   *
   *  Assuming this list:
   *
   *      language: html
   *      <ul id="cities">
   *        <li class="us" id="nyc">New York</li>
   *        <li class="uk" id="lon">London</li>
   *        <li class="us" id="chi">Chicago</li>
   *        <li class="jp" id="tok">Tokyo</li>
   *        <li class="us" id="la">Los Angeles</li>
   *        <li class="us" id="aus">Austin</li>
   *      </ul>
   *
   *  Then:
   *
   *      $p('nyc').adjacent('li.us');
   *      // -> [li#chi, li#la, li#aus]
   *      $p('nyc').adjacent('li.uk', 'li.jp');
   *      // -> [li#lon, li#tok]
  **/
  adjacent: function(element) {
    element = $p(element);
    var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
    return Prototype.Selector.select(expressions, element.parentNode).without(element);
  },

  /**
   *  Element.identify(@element) -> String
   *
   *  Returns `element`'s ID. If `element` does not have an ID, one is
   *  generated, assigned to `element`, and returned.
   *  
   *  ##### Examples
   *  
   *  Original HTML:
   *  
   *        <ul>
   *          <li id="apple">apple</li>
   *          <li>orange</li>
   *        </ul>
   *  
   *  JavaScript:
   *  
   *        $p('apple').identify();
   *        // -> 'apple'
   *      
   *        $p('apple').next().identify();
   *        // -> 'anonymous_element_1'
   *  
   *  Resulting HTML:
   *  
   *        <ul>
   *          <li id="apple">apple</li>
   *          <li id="anonymous_element_1">orange</li>
   *        </ul>
  **/
  identify: function(element) {
    element = $p(element);
    var id = Element.readAttribute(element, 'id');
    if (id) return id;
    do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id));
    Element.writeAttribute(element, 'id', id);
    return id;
  },

  /**
   *  Element.readAttribute(@element, attributeName) -> String | null
   *
   *  Returns the value of `element`'s `attribute` or `null` if `attribute` has
   *  not been specified.
   *  
   *  This method serves two purposes. First it acts as a simple wrapper around
   *  `getAttribute` which isn't a "real" function in Safari and Internet
   *  Explorer (it doesn't have `.apply` or `.call` for instance). Secondly, it
   *  cleans up the horrible mess Internet Explorer makes when handling
   *  attributes.
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <a id="tag" href="/tags/prototype" rel="tag" title="view related bookmarks." my_widget="some info.">Prototype</a>
   *
   *  Then:
   *
   *      $p('tag').readAttribute('href');
   *      // -> '/tags/prototype'
   *      
   *      $p('tag').readAttribute('title');
   *      // -> 'view related bookmarks.'
   *      
   *      $p('tag').readAttribute('my_widget');
   *      // -> 'some info.'
  **/
  readAttribute: function(element, name) {
    element = $p(element);
    if (Prototype.Browser.IE) {
      var t = Element._attributeTranslations.read;
      if (t.values[name]) return t.values[name](element, name);
      if (t.names[name]) name = t.names[name];
      if (name.include(':')) {
        return (!element.attributes || !element.attributes[name]) ? null :
         element.attributes[name].value;
      }
    }
    return element.getAttribute(name);
  },

  /**
   *  Element.writeAttribute(@element, attribute[, value = true]) -> Element
   *  Element.writeAttribute(@element, attributes) -> Element
   *
   *  Adds, specifies or removes attributes passed as either a hash or a
   *  name/value pair.
  **/
  writeAttribute: function(element, name, value) {
    element = $p(element);
    var attributes = { }, t = Element._attributeTranslations.write;

    if (typeof name == 'object') attributes = name;
    else attributes[name] = Object.isUndefined(value) ? true : value;

    for (var attr in attributes) {
      name = t.names[attr] || attr;
      value = attributes[attr];
      if (t.values[attr]) name = t.values[attr](element, value);
      if (value === false || value === null)
        element.removeAttribute(name);
      else if (value === true)
        element.setAttribute(name, name);
      else element.setAttribute(name, value);
    }
    return element;
  },

  /**
   *  Element.getHeight(@element) -> Number
   *
   *  Returns the height of `element`.
   *  
   *  This method returns correct values on elements whose display is set to
   *  `none` either in an inline style rule or in an CSS stylesheet.
   *  
   *  For performance reasons, if you need to query both width _and_ height of
   *  `element`, you should consider using [[Element.getDimensions]] instead.
   *  
   *  Note that the value returned is a _number only_ although it is
   *  _expressed in pixels_.
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <div id="rectangle" style="font-size: 10px; width: 20em; height: 10em"></div>
   *
   *  Then:
   *
   *      $p('rectangle').getHeight();
   *      // -> 100
  **/
	getHeight: function(element) {
		return $(element).height();
  	},
  /**
   *  Element.getWidth(@element) -> Number
   *
   *  Returns the width of `element`.
   *  
   *  This method returns correct values on elements whose display is set to
   *  `none` either in an inline style rule or in an CSS stylesheet.
   *  
   *  For performance reasons, if you need to query both width _and_ height of
   *  `element`, you should consider using [[Element.getDimensions]] instead.
   *  
   *  Note that the value returned is a _number only_ although it is
   *  _expressed in pixels_.
   *  
   *  ##### Examples
   *  
   *      language: html
   *      <div id="rectangle" style="font-size: 10px; width: 20em; height: 10em"></div>
   *
   *  Then:
   *
   *      $p('rectangle').getWidth();
   *      // -> 200
  **/
  getWidth: function(element) {
	  return $(element).width();
  },
  /**
   *  Element.getDimensions@element() -> Object
   *
   *  Returns an object containing viewport dimensions in the form
   *  `{ width: Number, height: Number }`.
   *
   *  The _viewport_ is the subset of the browser window that a page occupies
   *  &mdash; the "usable" space in a browser window.
   *  
   *  ##### Example
   *  
   *      document.viewport.getDimensions();
   *      //-> { width: 776, height: 580 }
  **/
	getDimensions: function(element){
		return {0: $(element).width(), width: $(element).width(), 1:$(element).height(), height:$(element).height()};
	},
  
	positionOffset: function(){
		return $(element).position();  
	},
	  
	cumulativeOffset: function(element){
		return $(element).offset();
	},
  /**
   *  Element.addClassName(@element, className) -> Element
   *  - className (String): The class name to add.
   *
   *  Adds the given CSS class to `element`.
   *
   *  ##### Example
   *
   *  Assuming this HTML:
   *
   *      language: html
   *      <div id="mutsu" class="apple fruit"></div>
   *
   *  Then:
   *
   *      $p('mutsu').className;
   *      // -> 'apple fruit'
   *      $p('mutsu').addClassName('food');
   *      $p('mutsu').className;
   *      // -> 'apple fruit food'
  **/
  addClassName: function(element, className) {
    if (!(element = $p(element))) return;
    if (!Element.hasClassName(element, className))
      element.className += (element.className ? ' ' : '') + className;
    return element;
  },

  /**
   *  Element.removeClassName(@element, className) -> Element
   *
   *  Removes CSS class `className` from `element`.
   *
   *  ##### Examples
   *
   *  Assuming this HTML:
   *
   *      language: html
   *      <div id="mutsu" class="apple fruit food"></div>
   *  
   *  Then:
   *
   *      $p('mutsu').removeClassName('food');
   *      // -> Element
   *      
   *      $p('mutsu').classNames;
   *      // -> 'apple fruit'
  **/
  removeClassName: function(element, className) {
    if (!(element = $p(element))) return;
    element.className = element.className.replace(
      new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
    return element;
  },
  /**
   *  Element.empty(@element) -> Element
   *
   *  Tests whether `element` is empty (i.e., contains only whitespace).
   *  
   *  ##### Examples
   *  
   *      <div id="wallet">     </div>
   *      <div id="cart">full!</div>
   *  
   *      $p('wallet').empty();
   *      // -> true
   *
   *      $p('cart').empty();
   *      // -> false
  **/
  empty: function(element) {
    return $p(element).innerHTML.blank();
  },

  /**
   *  Element.descendantOf(@element, ancestor) -> Boolean
   *  - ancestor (Element | String): The element to check against (or its ID).
   *
   *  Checks if `element` is a descendant of `ancestor`.
   *
   *  ##### Example
   *
   *  Assuming:
   *
   *      language: html
   *      <div id="australopithecus">
   *        <div id="homo-erectus">
   *          <div id="homo-sapiens"></div>
   *        </div>
   *      </div>
   *
   *  Then:
   *
   *      $p('homo-sapiens').descendantOf('australopithecus');
   *      // -> true
   *
   *      $p('homo-erectus').descendantOf('homo-sapiens');
   *      // -> false
  **/
  descendantOf: function(element, ancestor) {
    element = $p(element), ancestor = $p(ancestor);

    if (element.compareDocumentPosition)
      return (element.compareDocumentPosition(ancestor) & 8) === 8;

    if (ancestor.contains)
      return ancestor.contains(element) && ancestor !== element;

    while (element = element.parentNode)
      if (element == ancestor) return true;

    return false;
  },

  /**
   *  Element.scrollTo(@element) -> Element
   *
   *  Scrolls the window so that `element` appears at the top of the viewport.
   *  
   *  This has a similar effect than what would be achieved using
   *  [HTML anchors](http://www.w3.org/TR/html401/struct/links.html#h-12.2.3)
   *  (except the browser's history is not modified).
   *  
   *  ##### Example
   *  
   *      $p(element).scrollTo();
   *      // -> Element
  **/
  scrollTo: function(element) {
    element = $p(element);
    var pos = Element.cumulativeOffset(element);
    window.scrollTo(pos[0], pos[1]);
    return element;
  },

  /**
   *  Element.getStyle(@element, style) -> String | null
   *  - style (String): The property name to be retrieved.
   *
   *  Returns the given CSS property value of `element`. The property can be
   *  specified in either its CSS form (`font-size`) or its camelized form
   *  (`fontSize`).
   *
   *  This method looks up the CSS property of an element whether it was
   *  applied inline or in a stylesheet. It works around browser inconsistencies
   *  regarding `float`, `opacity`, which returns a value between `0`
   *  (fully transparent) and `1` (fully opaque), position properties
   *  (`left`, `top`, `right` and `bottom`) and when getting the dimensions
   *  (`width` or `height`) of hidden elements.
   *  
   *  ##### Examples
   *  
   *      $p(element).getStyle('font-size');
   *      // equivalent:
   *      
   *      $p(element).getStyle('fontSize');
   *      // -> '12px'
   *  
   *  ##### Notes
   *  
   *  Internet Explorer returns literal values while other browsers return
   *  computed values.
   *
   *  Consider the following HTML snippet:
   *  
   *      language: html
   *      <style>
   *        #test {
   *          font-size: 12px;
   *          margin-left: 1em;
   *        }
   *      </style>
   *      <div id="test"></div>
   *
   *  Then:
   *
   *      $p('test').getStyle('margin-left');
   *      // -> '1em' in Internet Explorer,
   *      // -> '12px' elsewhere.
   *  
   *  Safari returns `null` for *any* non-inline property if the element is
   *  hidden (has `display` set to `'none'`).
   *  
   *  Not all CSS shorthand properties are supported. You may only use the CSS
   *  properties described in the
   *  [Document Object Model (DOM) Level 2 Style Specification](http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-ElementCSSInlineStyle).
   **/
  getStyle: function(element, style) {
    element = $p(element);
    style = style == 'float' ? 'cssFloat' : style.camelize();
    var value = element.style[style];
    if (!value || value == 'auto') {
      var css = document.defaultView.getComputedStyle(element, null);
      value = css ? css[style] : null;
    }
    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
    return value == 'auto' ? null : value;
  },

  /**
   *  Element.getOpacity(@element) -> String | null
   *
   *  Returns the opacity of the element.
  **/
  getOpacity: function(element) {
    return $p(element).getStyle('opacity');
  },

  /** 
   *  Element.setStyle(@element, styles) -> Element
   *  
   *  Modifies `element`'s CSS style properties. Styles are passed as a hash of
   *  property-value pairs in which the properties are specified in their
   *  camelized form.
   *  
   *  ##### Examples
   *  
   *      $p(element).setStyle({
   *        backgroundColor: '#900',
   *        fontSize: '12px'
   *      });
   *      // -> Element
   *  
   *  ##### Notes
   *  
   *  The method transparently deals with browser inconsistencies for `float`
   *  (however, as `float` is a reserved keyword, you must either escape it or
   *  use `cssFloat` instead) and `opacity` (which accepts values between `0`
   *  -fully transparent- and `1` -fully opaque-). You can safely use either of
   *  the following across all browsers:
   *  
   *      $p(element).setStyle({
   *        cssFloat: 'left',
   *        opacity: 0.5
   *      });
   *      // -> Element
   *      
   *      $p(element).setStyle({
   *        'float': 'left', // notice how float is surrounded by single quotes
   *        opacity: 0.5
   *      });
   *      // -> Element
   *  
   *  Not all CSS shorthand properties are supported. You may only use the CSS
   *  properties described in the
   *  [Document Object Model (DOM) Level 2 Style Specification](http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-ElementCSSInlineStyle).
  **/
  setStyle: function(element, styles) {
    element = $p(element);
    var elementStyle = element.style, match;
    if (Object.isString(styles)) {
      element.style.cssText += ';' + styles;
      return styles.include('opacity') ?
        element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
    }
    for (var property in styles)
      if (property == 'opacity') element.setOpacity(styles[property]);
      else
        elementStyle[(property == 'float' || property == 'cssFloat') ?
          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
            property] = styles[property];

    return element;
  },

  /** 
   *  Element.setOpacity(@element, opacity) -> [Element...]
   *  
   *  Sets the visual opacity of an element while working around inconsistencies
   *  in various browsers. The `opacity` argument should be a floating point
   *  number, where the value of `0` is fully transparent and `1` is fully opaque.
   *  
   *  [[Element.setStyle]] method uses [[Element.setOpacity]] internally when needed.
   *  
   *  ##### Examples
   *  
   *      var element = $p('myelement');
   *      // set to 50% transparency
   *      element.setOpacity(0.5);
   *      
   *      // these are equivalent, but allow for setting more than
   *      // one CSS property at once:
   *      element.setStyle({ opacity: 0.5 });
   *      element.setStyle("opacity: 0.5");
  **/
  setOpacity: function(element, value) {
    element = $p(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;
    return element;
  },

  /**
   *  Element.makePositioned(@element) -> Element
   *
   *  Allows for the easy creation of a CSS containing block by setting
   *  `element`'s CSS `position` to `relative` if its initial position is
   *  either `static` or `undefined`.
   *  
   *  To revert back to `element`'s original CSS position, use
   *  [[Element.undoPositioned]].
  **/
  makePositioned: function(element) {
    element = $p(element);
    var pos = Element.getStyle(element, 'position');
    if (pos == 'static' || !pos) {
      element._madePositioned = true;
      element.style.position = 'relative';
      // Opera returns the offset relative to the positioning context, when an
      // element is position relative but top and left have not been defined
      if (Prototype.Browser.Opera) {
        element.style.top = 0;
        element.style.left = 0;
      }
    }
    return element;
  },

  /**
   *  Element.undoPositioned(@element) -> Element
   *
   *  Sets `element` back to the state it was in _before_
   *  [[Element.makePositioned]] was applied to it.
   *  
   *  `element`'s absolutely positioned children will now have their positions
   *  set relatively to `element`'s nearest ancestor with a CSS `position` of
   *  `'absolute'`, `'relative'` or `'fixed'`.
  **/
  undoPositioned: function(element) {
    element = $p(element);
    if (element._madePositioned) {
      element._madePositioned = undefined;
      element.style.position =
        element.style.top =
        element.style.left =
        element.style.bottom =
        element.style.right = '';
    }
    return element;
  },

  /**
   *  Element.makeClipping(@element) -> Element
   *
   *  Simulates the poorly-supported CSS `clip` property by setting `element`'s
   *  `overflow` value to `hidden`.
   *
   *  To undo clipping, use [[Element.undoClipping]].
   *  
   *  The visible area is determined by `element`'s width and height.
   *  
   *  ##### Example
   *  
   *      language:html
   *      <div id="framer">
   *        <img src="/assets/2007/1/14/chairs.jpg" alt="example" />
   *      </div>
   *  
   *  Then:
   *
   *      $p('framer').makeClipping().setStyle({width: '100px', height: '100px'});
   *      // -> Element
   *  
   *  Another example:
   *
   *      language: html
   *      <a id="clipper" href="#">Click me to try it out.</a>
   *  
   *      <div id="framer">
   *        <img src="/assets/2007/2/24/chairs.jpg" alt="example" />
   *      </div>
   *  
   *      <script type="text/javascript" charset="utf-8">
   *        var Example = {
   *          clip: function(){
   *            $p('clipper').update('undo clipping!');
   *            $p('framer').makeClipping().setStyle({width: '100px', height: '100px'});
   *          },
   *          unClip: function(){
   *            $p('clipper').update('clip!');
   *            $p('framer').undoClipping();
   *          },
   *          toggleClip: function(event){
   *            if($('clipper').innerHTML == 'undo clipping!') Example.unClip();
   *            else Example.clip();
   *            Event.stop(event);
   *          }
   *        };
   *        Event.observe('clipper', 'click', Example.toggleClip);
   *      </script>
  **/
  makeClipping: function(element) {
    element = $p(element);
    if (element._overflow) return element;
    element._overflow = Element.getStyle(element, 'overflow') || 'auto';
    if (element._overflow !== 'hidden')
      element.style.overflow = 'hidden';
    return element;
  },

  /**
   *  Element.undoClipping(@element) -> Element
   *
   *  Sets `element`'s CSS `overflow` property back to the value it had
   *  _before_ [[Element.makeClipping]] was applied.
   *
   *  ##### Example
   *  
   *      language: html
   *      <div id="framer">
   *        <img src="/assets/2007/1/14/chairs.jpg" alt="example" />
   *      </div>
   *
   *  Then:
   *
   *      $p('framer').undoClipping();
   *      // -> Element (and sets the CSS overflow property to its original value).
   *  
   *  Another example:
   *
   *      language: html
   *      <a id="clipper" href="#">Click me to try it out.</a>
   *
   *      <div id="framer">
   *        <img src="/assets/2007/2/24/chairs_1.jpg" alt="example" />
   *      </div>
   *  
   *      <script type="text/javascript" charset="utf-8">
   *        var Example = {
   *          clip: function(){
   *            $p('clipper').update('undo clipping!');
   *            $p('framer').makeClipping().setStyle({width: '100px', height: '100px'});
   *          },
   *          unClip: function(){
   *            $p('clipper').update('clip!');
   *            $p('framer').undoClipping();
   *          },
   *          toggleClip: function(event){
   *            if($('clipper').innerHTML == 'clip!') Example.clip();
   *            else Example.unClip();
   *            Event.stop(event);
   *          }
   *        };
   *        $p('framer').makeClipping().setStyle({width: '100px', height: '100px'});
   *        Event.observe('clipper', 'click', Example.toggleClip);
   *      </script>
  **/
  undoClipping: function(element) {
    element = $p(element);
    if (!element._overflow) return element;
    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
    element._overflow = null;
    return element;
  },

  /**
   *  Element.clonePosition(@element, source[, options]) -> Element
   *  - source (Element | String): The source element (or its ID).
   *  - options (Object): The position fields to clone.
   *
   *  Clones the position and/or dimensions of `source` onto the element as
   *  defined by `options`, with an optional offset for the `left` and `top`
   *  properties.
   *
   *  Note that the element will be positioned exactly like `source` whether or
   *  not it is part of the same [CSS containing
   *  block](http://www.w3.org/TR/CSS21/visudet.html#containing-block-details).
   *
   *  ##### Options
   *
   *  <table class='options'>
   *  <thead>
   *    <tr>
   *      <th style='text-align: left; padding-right: 1em'>Name</th>
   *      <th style='text-align: left; padding-right: 1em'>Default</th>
   *      <th style='text-align: left; padding-right: 1em'>Description</th>
   *    </tr>
   *  </thead>
   *  <tbody>
   *    <tr>
   *    <td><code>setLeft</code></td>
   *    <td><code>true</code></td>
   *  <td>Clones <code>source</code>'s <code>left</code> CSS property onto <code>element</code>.</td>
   *  </tr>
   *  <tr>
   *    <td><code>setTop</code></td>
   *    <td><code>true</code></td>
   *  <td>Clones <code>source</code>'s <code>top</code> CSS property onto <code>element</code>.</td>
   *  </tr>
   *  <tr>
   *    <td><code>setWidth</code></td>
   *    <td><code>true</code></td>
   *  <td>Clones <code>source</code>'s <code>width</code> onto <code>element</code>.</td>
   *  </tr>
   *  <tr>
   *    <td><code>setHeight</code></td>
   *    <td><code>true</code></td>
   *  <td>Clones <code>source</code>'s <code>width</code> onto <code>element</code>.</td>
   *  </tr>
   *  <tr>
   *    <td><code>offsetLeft</code></td>
   *    <td><code>0</code></td>
   *  <td>Number by which to offset <code>element</code>'s <code>left</code> CSS property.</td>
   *  </tr>
   *  <tr>
   *    <td><code>offsetTop</code></td>
   *    <td><code>0</code></td>
   *  <td>Number by which to offset <code>element</code>'s <code>top</code> CSS property.</td>
   *  </tr>
   *  </tbody>
   *  </table>
  **/
  clonePosition: function(element, source) {
    var options = Object.extend({
      setLeft:    true,
      setTop:     true,
      setWidth:   true,
      setHeight:  true,
      offsetTop:  0,
      offsetLeft: 0
    }, arguments[2] || { });

    // find page position of source
    source = $p(source);
    var p = Element.viewportOffset(source), delta = [0, 0], parent = null;

    // find coordinate system to use
    element = $p(element);
    
    // delta [0,0] will do fine with position: fixed elements,
    // position:absolute needs offsetParent deltas
    if (Element.getStyle(element, 'position') == 'absolute') {
      parent = Element.getOffsetParent(element);
      delta = Element.viewportOffset(parent);
    }

    // correct by body offsets (fixes Safari)
    if (parent == document.body) {
      delta[0] -= document.body.offsetLeft;
      delta[1] -= document.body.offsetTop;
    }

    // set position
    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
    if (options.setHeight) element.style.height = source.offsetHeight + 'px';
    return element;
  }
};

Object.extend(Element.Methods, {
  /** alias of: Element.select
   *  Element.getElementsBySelector(@element, selector) -> [Element...]
  **/
  getElementsBySelector: Element.Methods.select,

  /**
   *  Element.childElements(@element) -> [Element...]
   *
   *  Collects all of the element's children and returns them as an array of
   *  [[Element.extended extended]] elements, in document order. The first
   *  entry in the array is the topmost child of `element`, the next is the
   *  child after that, etc.
   *
   *  Like all of Prototype's DOM traversal methods, [[Element.childElements]]
   *  ignores text nodes and returns element nodes only.
   *
   *  ##### Example
   *
   *  Assuming:
   *
   *      language: html
   *      <div id="australopithecus">
   *        Some text in a text node
   *        <div id="homo-erectus">
   *          <div id="homo-neanderthalensis"></div>
   *          <div id="homo-sapiens"></div>
   *        </div>
   *      </div>
   *
   *  Then:
   *
   *      $p('australopithecus').childElements();
   *      // -> [div#homo-erectus]
   *
   *      $p('homo-erectus').childElements();
   *      // -> [div#homo-neanderthalensis, div#homo-sapiens]
   *
   *      $p('homo-sapiens').childElements();
   *      // -> []
  **/
  childElements: Element.Methods.immediateDescendants
});

Element._attributeTranslations = {
  write: {
    names: {
      className: 'class',
      htmlFor:   'for'
    },
    values: { }
  }
};

if (Prototype.Browser.Opera) {
  Element.Methods.getStyle = Element.Methods.getStyle.wrap(
    function(proceed, element, style) {
      switch (style) {
        case 'height': case 'width':
          // returns '0px' for hidden elements; we want it to return null
          if (!Element.visible(element)) return null;

          // returns the border-box dimensions rather than the content-box
          // dimensions, so we subtract padding and borders from the value
          var dim = parseInt(proceed(element, style), 10);

          if (dim !== element['offset' + style.capitalize()])
            return dim + 'px';

          var properties;
          if (style === 'height') {
            properties = ['border-top-width', 'padding-top',
             'padding-bottom', 'border-bottom-width'];
          }
          else {
            properties = ['border-left-width', 'padding-left',
             'padding-right', 'border-right-width'];
          }
          return properties.inject(dim, function(memo, property) {
            var val = proceed(element, property);
            return val === null ? memo : memo - parseInt(val, 10);
          }) + 'px';
        default: return proceed(element, style);
      }
    }
  );

  Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
    function(proceed, element, attribute) {
      if (attribute === 'title') return element.title;
      return proceed(element, attribute);
    }
  );
}

else if (Prototype.Browser.IE) {
  Element.Methods.getStyle = function(element, style) {
    element = $p(element);
    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
    var value = element.style[style];
    if (!value && element.currentStyle) value = element.currentStyle[style];

    if (style == 'opacity') {
      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
        if (value[1]) return parseFloat(value[1]) / 100;
      return 1.0;
    }

    if (value == 'auto') {
      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
        return element['offset' + style.capitalize()] + 'px';
      return null;
    }
    return value;
  };

  Element.Methods.setOpacity = function(element, value) {
    function stripAlpha(filter){
      return filter.replace(/alpha\([^\)]*\)/gi,'');
    }
    element = $p(element);
    var currentStyle = element.currentStyle;
    if ((currentStyle && !currentStyle.hasLayout) ||
      (!currentStyle && element.style.zoom == 'normal'))
        element.style.zoom = 1;

    var filter = element.getStyle('filter'), style = element.style;
    if (value == 1 || value === '') {
      (filter = stripAlpha(filter)) ?
        style.filter = filter : style.removeAttribute('filter');
      return element;
    } else if (value < 0.00001) value = 0;
    style.filter = stripAlpha(filter) +
      'alpha(opacity=' + (value * 100) + ')';
    return element;
  };

  Element._attributeTranslations = (function(){

    var classProp = 'className', 
        forProp = 'for', 
        el = document.createElement('div');

    // try "className" first (IE <8)
    el.setAttribute(classProp, 'x');

    if (el.className !== 'x') {
      // try "class" (IE 8)
      el.setAttribute('class', 'x');
      if (el.className === 'x') {
        classProp = 'class';
      }
    }
    el = null;

    el = document.createElement('label');
    el.setAttribute(forProp, 'x');
    if (el.htmlFor !== 'x') {
      el.setAttribute('htmlFor', 'x');
      if (el.htmlFor === 'x') {
        forProp = 'htmlFor';
      }
    }
    el = null;

    return {
      read: {
        names: {
          'class':      classProp,
          'className':  classProp,
          'for':        forProp,
          'htmlFor':    forProp
        },
        values: {
          _getAttr: function(element, attribute) {
            return element.getAttribute(attribute);
          },
          _getAttr2: function(element, attribute) {
            return element.getAttribute(attribute, 2);
          },
          _getAttrNode: function(element, attribute) {
            var node = element.getAttributeNode(attribute);
            return node ? node.value : "";
          },
          _getEv: (function(){

            var el = document.createElement('div'), f;
            el.onclick = Prototype.emptyFunction;
            var value = el.getAttribute('onclick');

            // IE<8
            if (String(value).indexOf('{') > -1) {
              // intrinsic event attributes are serialized as `function { ... }`
              f = function(element, attribute) {
                attribute = element.getAttribute(attribute);
                if (!attribute) return null;
                attribute = attribute.toString();
                attribute = attribute.split('{')[1];
                attribute = attribute.split('}')[0];
                return attribute.strip();
              };
            }
            // IE8
            else if (value === '') {
              // only function body is serialized
              f = function(element, attribute) {
                attribute = element.getAttribute(attribute);
                if (!attribute) return null;
                return attribute.strip();
              };
            }
            el = null;
            return f;
          })(),
          _flag: function(element, attribute) {
            return $p(element).hasAttribute(attribute) ? attribute : null;
          },
          style: function(element) {
            return element.style.cssText.toLowerCase();
          },
          title: function(element) {
            return element.title;
          }
        }
      }
    }
  })();

  Element._attributeTranslations.write = {
    names: Object.extend({
      cellpadding: 'cellPadding',
      cellspacing: 'cellSpacing'
    }, Element._attributeTranslations.read.names),
    values: {
      checked: function(element, value) {
        element.checked = !!value;
      },

      style: function(element, value) {
        element.style.cssText = value ? value : '';
      }
    }
  };

  Element._attributeTranslations.has = {};

  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
  });

  (function(v) {
    Object.extend(v, {
      href:        v._getAttr2,
      src:         v._getAttr2,
      type:        v._getAttr,
      action:      v._getAttrNode,
      disabled:    v._flag,
      checked:     v._flag,
      readonly:    v._flag,
      multiple:    v._flag,
      onload:      v._getEv,
      onunload:    v._getEv,
      onclick:     v._getEv,
      ondblclick:  v._getEv,
      onmousedown: v._getEv,
      onmouseup:   v._getEv,
      onmouseover: v._getEv,
      onmousemove: v._getEv,
      onmouseout:  v._getEv,
      onfocus:     v._getEv,
      onblur:      v._getEv,
      onkeypress:  v._getEv,
      onkeydown:   v._getEv,
      onkeyup:     v._getEv,
      onsubmit:    v._getEv,
      onreset:     v._getEv,
      onselect:    v._getEv,
      onchange:    v._getEv
    });
  })(Element._attributeTranslations.read.values);

  // We optimize Element#down for IE so that it does not call
  // Element#descendants (and therefore extend all nodes).
  if (Prototype.BrowserFeatures.ElementExtensions) {
    (function() {
      function _descendants(element) {
        var nodes = element.getElementsByTagName('*'), results = [];
        for (var i = 0, node; node = nodes[i]; i++)
          if (node.tagName !== "!") // Filter out comment nodes.
            results.push(node);
        return results;
      }

      Element.Methods.down = function(element, expression, index) {
        element = $p(element);
        if (arguments.length == 1) return element.firstDescendant();
        return Object.isNumber(expression) ? _descendants(element)[expression] :
          Element.select(element, expression)[index || 0];
      }
    })();
  }

}

else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
  Element.Methods.setOpacity = function(element, value) {
    element = $p(element);
    element.style.opacity = (value == 1) ? 0.999999 :
      (value === '') ? '' : (value < 0.00001) ? 0 : value;
    return element;
  };
}

else if (Prototype.Browser.WebKit) {
  Element.Methods.setOpacity = function(element, value) {
    element = $p(element);
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;

    if (value == 1)
      if (element.tagName.toUpperCase() == 'IMG' && element.width) {
        element.width++; element.width--;
      } else try {
        var n = document.createTextNode(' ');
        element.appendChild(n);
        element.removeChild(n);
      } catch (e) { }

    return element;
  };
}

if ('outerHTML' in document.documentElement) {
  Element.Methods.replace = function(element, content) {
    element = $p(element);

    if (content && content.toElement) content = content.toElement();
    if (Object.isElement(content)) {
      element.parentNode.replaceChild(content, element);
      return element;
    }

    content = Object.toHTML(content);
    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();

    if (Element._insertionTranslations.tags[tagName]) {
      var nextSibling = element.next(),
          fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
      parent.removeChild(element);
      if (nextSibling)
        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
      else
        fragments.each(function(node) { parent.appendChild(node) });
    }
    else element.outerHTML = content.stripScripts();

    content.evalScripts.bind(content).defer();
    return element;
  };
}

Element._returnOffset = function(l, t) {
  var result = [l, t];
  result.left = l;
  result.top = t;
  return result;
};

Element._getContentFromAnonymousElement = function(tagName, html, force) {
  var div = new Element('div'), 
      t = Element._insertionTranslations.tags[tagName];
  
  var workaround = false;
  if (t) workaround = true;
  else if (force) {
    workaround = true;
    t = ['', '', 0];
  }
      
  if (workaround) {
    // Adding a text node to the beginning of the string (then removing it)
    // fixes an issue in Internet Explorer. See Element#update above.
    div.innerHTML = '&nbsp;' + t[0] + html + t[1];
    div.removeChild(div.firstChild);
    for (var i = t[2]; i--; ) {
      div = div.firstChild;
    }
  }
  else {
    div.innerHTML = html;
  }
  return $A(div.childNodes);
};

Element._insertionTranslations = {
  before: function(element, node) {
    element.parentNode.insertBefore(node, element);
  },
  top: function(element, node) {
    element.insertBefore(node, element.firstChild);
  },
  bottom: function(element, node) {
    element.appendChild(node);
  },
  after: function(element, node) {
    element.parentNode.insertBefore(node, element.nextSibling);
  },
  tags: {
    TABLE:  ['<table>',                '</table>',                   1],
    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
    SELECT: ['<select>',               '</select>',                  1]
  }
};

(function() {
  var tags = Element._insertionTranslations.tags;
  Object.extend(tags, {
    THEAD: tags.TBODY,
    TFOOT: tags.TBODY,
    TH:    tags.TD
  });
})();

Element.Methods.Simulated = {
  /**
   *  Element.hasAttribute(@element, attribute) -> Boolean
   *  
   *  Simulates the standard compliant DOM method
   *  [`hasAttribute`](http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-ElHasAttr)
   *  for browsers missing it (Internet Explorer 6 and 7).
   *  
   *  ##### Example
   *  
   *      language: html
   *      <a id="link" href="http://prototypejs.org">Prototype</a>
   *
   *  Then:
   *
   *      $p('link').hasAttribute('href');
   *      // -> true
  **/  
  hasAttribute: function(element, attribute) {
    attribute = Element._attributeTranslations.has[attribute] || attribute;
    var node = $p(element).getAttributeNode(attribute);
    return !!(node && node.specified);
  }
};

Element.Methods.ByTag = { };

Object.extend(Element, Element.Methods);

(function(div) {

  if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) {
    window.HTMLElement = { };
    window.HTMLElement.prototype = div['__proto__'];
    Prototype.BrowserFeatures.ElementExtensions = true;
  }

  div = null;

})(document.createElement('div'));

/**
 *  Element.extend(element) -> Element
 *
 *  Extends the given element instance with all of the Prototype goodness and
 *  syntactic sugar, as well as any extensions added via [[Element.addMethods]].
 *  (If the element instance was already extended, this is a no-op.)
 *
 *  You only need to use [[Element.extend]] on element instances you've acquired
 *  directly from the DOM; **all** Prototype methods that return element
 *  instances (such as [[$]], [[Element.down]], etc.) will pre-extend the
 *  element before returning it.
 *
 *  Check out ["How Prototype extends the
 *  DOM"](http://prototypejs.org/learn/extensions) for more about element
 *  extensions.
 *
 *  ##### Details
 *
 *  Specifically, [[Element.extend]] extends the given instance with the methods
 *  contained in [[Element.Methods]] and `Element.Methods.Simulated`. If `element`
 *  is an `input`, `textarea`, or `select` element, it will also be extended
 *  with the methods from `Form.Element.Methods`. If it is a `form` element, it
 *  will also be extended with the methods from `Form.Methods`.
**/
Element.extend = (function() {

  function checkDeficiency(tagName) {
    if (typeof window.Element != 'undefined') {
      var proto = window.Element.prototype;
      if (proto) {
        var id = '_' + (Math.random()+'').slice(2),
            el = document.createElement(tagName);
        proto[id] = 'x';
        var isBuggy = (el[id] !== 'x');
        delete proto[id];
        el = null;
        return isBuggy;
      }
    }
    return false;
  }

  function extendElementWith(element, methods) {
    for (var property in methods) {
      var value = methods[property];
      if (Object.isFunction(value) && !(property in element))
        element[property] = value.methodize();
    }
  }

  var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object');

  if (Prototype.BrowserFeatures.SpecificElementExtensions) {
    // IE8 has a bug with `HTMLObjectElement` and `HTMLAppletElement` objects
    // not being able to "inherit" from `Element.prototype`
    // or a specific prototype - `HTMLObjectElement.prototype`, `HTMLAppletElement.prototype`
    if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) {
      return function(element) {
        if (element && typeof element._extendedByPrototype == 'undefined') {
          var t = element.tagName;
          if (t && (/^(?:object|applet|embed)$/i.test(t))) {
            extendElementWith(element, Element.Methods);
            extendElementWith(element, Element.Methods.Simulated);
            extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
          }
        }
        return element;
      }
    }
    return Prototype.K;
  }

  var Methods = { }, ByTag = Element.Methods.ByTag;

  var extend = Object.extend(function(element) {
    // need to use actual `typeof` operator
    // to prevent errors in some environments (when accessing node expandos)
    if (!element || typeof element._extendedByPrototype != 'undefined' ||
        element.nodeType != 1 || element == window) return element;

    var methods = Object.clone(Methods),
        tagName = element.tagName.toUpperCase();

    // extend methods for specific tags
    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);

    extendElementWith(element, methods);

    element._extendedByPrototype = Prototype.emptyFunction;
    return element;

  }, {
    refresh: function() {
      // extend methods for all tags (Safari doesn't need this)
      if (!Prototype.BrowserFeatures.ElementExtensions) {
        Object.extend(Methods, Element.Methods);
        Object.extend(Methods, Element.Methods.Simulated);
      }
    }
  });

  extend.refresh();
  return extend;
})();

if (document.documentElement.hasAttribute) {
  Element.hasAttribute = function(element, attribute) {
    return element.hasAttribute(attribute);
  };
}
else {
  Element.hasAttribute = Element.Methods.Simulated.hasAttribute;
}

/**
 *  Element.addMethods(methods) -> undefined
 *  Element.addMethods(tagName, methods) -> undefined
 *  - tagName (String): (Optional) The name of the HTML tag for which the
 *    methods should be available; if not given, all HTML elements will have
 *    the new methods.
 *  - methods (Object): A hash of methods to add.
 *
 *  [[Element.addMethods]] makes it possible to mix your *own* methods into the
 *  [[Element]] object and extended element instances (all of them, or only ones
 *  with the given HTML tag if you specify `tagName`).
 *
 *  You define the methods in a hash that you provide to [[Element.addMethods]].
 *  Here's an example adding two methods:
 *
 *      Element.addMethods({
 *
 *        // myOwnMethod: Do something cool with the element
 *        myOwnMethod: function(element) {
 *          if (!(element = $p(element))) return;
 *          // ...do smething with 'element'...
 *          return element;
 *        },
 *
 *        // wrap: Wrap the element in a new element using the given tag
 *        wrap: function(element, tagName) {
 *          var wrapper;
 *          if (!(element = $p(element))) return;
 *          wrapper = new Element(tagName);
 *          element.parentNode.replaceChild(wrapper, element);
 *          wrapper.appendChild(element);
 *          return wrapper;
 *        }
 *
 *      });
 *
 *  Once added, those can be used either via [[Element]]:
 *
 *      // Wrap the element with the ID 'foo' in a div
 *      Element.wrap('foo', 'div');
 *
 *  ...or as instance methods of extended elements:
 *
 *      // Wrap the element with the ID 'foo' in a div
 *      $p('foo').wrap('div');
 *
 *  Note the following requirements and conventions for methods added to
 *  [[Element]]:
 *
 *  - The first argument is *always* an element or ID, by convention this
 *    argument is called `element`.
 *  - The method passes the `element` argument through [[$]] and typically
 *    returns if the result is undefined.
 *  - Barring a good reason to return something else, the method returns the
 *    extended element to enable chaining.
 *
 *  Our `myOwnMethod` method above returns the element because it doesn't have
 *  a good reason to return anything else. Our `wrap` method returns the
 *  wrapper, because that makes more sense for that method.
 *
 *  ##### Extending only specific elements
 *
 *  If you call [[Element.addMethods]] with *two* arguments, it will apply the
 *  methods only to elements with the given HTML tag:
 *
 *      Element.addMethods('DIV', my_div_methods);
 *      // the given methods are now available on DIV elements, but not others
 *
 *  You can also pass an *[[Array]]* of tag names as the first argument:
 *
 *      Element.addMethods(['DIV', 'SPAN'], my_additional_methods);
 *      // DIV and SPAN now both have the given methods
 *
 *  (Tag names in the first argument are not case sensitive.)
 *
 *  Note: [[Element.addMethods]] has built-in security which prevents you from
 *  overriding native element methods or properties (like `getAttribute` or
 *  `innerHTML`), but nothing prevents you from overriding one of Prototype's
 *  methods. Prototype uses a lot of its methods internally; overriding its
 *  methods is best avoided or at least done only with great care.
 *
 *  ##### Example 1
 *
 *  Our `wrap` method earlier was a complete example. For instance, given this
 *  paragraph:
 *
 *      language: html
 *      <p id="first">Some content...</p>
 *
 *  ...we might wrap it in a `div`:
 *
 *      $p('first').wrap('div');
 *
 *  ...or perhaps wrap it and apply some style to the `div` as well:
 *
 *      $p('first').wrap('div').setStyle({
 *        backgroundImage: 'url(images/rounded-corner-top-left.png) top left'
 *      });
 *
 *  ##### Example 2
 *
 *  We can add a method to elements that makes it a bit easier to update them
 *  via [[Ajax.Updater]]:
 *
 *      Element.addMethods({
 *        ajaxUpdate: function(element, url, options) {
 *          if (!(element = $p(element))) return;
 *          element.update('<img src="/images/spinner.gif" alt="Loading...">');
 *          options = options || {};
 *          options.onFailure = options.onFailure || defaultFailureHandler.curry(element);
 *          new Ajax.Updater(element, url, options);
 *          return element;
 *        }
 *      });
 *
 *  Now we can update an element via an Ajax call much more concisely than
 *  before:
 *
 *      $p('foo').ajaxUpdate('/new/content');
 *
 *  That will use [[Ajax.Updater]] to load new content into the 'foo' element,
 *  showing a spinner while the call is in progress. It even applies a default
 *  failure handler (since we didn't supply one).
**/
Element.addMethods = function(methods) {
  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
  
  if (arguments.length == 2) {
    var tagName = methods;
    methods = arguments[1];
  }

  if (!tagName) Object.extend(Element.Methods, methods || { });
  else {
    if (Object.isArray(tagName)) tagName.each(extend);
    else extend(tagName);
  }

  function extend(tagName) {
    tagName = tagName.toUpperCase();
    if (!Element.Methods.ByTag[tagName])
      Element.Methods.ByTag[tagName] = { };
    Object.extend(Element.Methods.ByTag[tagName], methods);
  }

  function copy(methods, destination, onlyIfAbsent) {
    onlyIfAbsent = onlyIfAbsent || false;
    for (var property in methods) {
      var value = methods[property];
      if (!Object.isFunction(value)) continue;
      if (!onlyIfAbsent || !(property in destination))
        destination[property] = value.methodize();
    }
  }

  function findDOMClass(tagName) {
    var klass;
    var trans = {
      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
      "FrameSet", "IFRAME": "IFrame"
    };
    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName + 'Element';
    if (window[klass]) return window[klass];
    klass = 'HTML' + tagName.capitalize() + 'Element';
    if (window[klass]) return window[klass];

    var element = document.createElement(tagName),
        proto = element['__proto__'] || element.constructor.prototype;
        
    element = null;
    return proto;
  }

  var elementPrototype = window.HTMLElement ? HTMLElement.prototype :
   Element.prototype;

  if (F.ElementExtensions) {
    copy(Element.Methods, elementPrototype);
    copy(Element.Methods.Simulated, elementPrototype, true);
  }

  if (F.SpecificElementExtensions) {
    for (var tag in Element.Methods.ByTag) {
      var klass = findDOMClass(tag);
      if (Object.isUndefined(klass)) continue;
      copy(T[tag], klass.prototype);
    }
  }

  Object.extend(Element, Element.Methods);
  delete Element.ByTag;

  if (Element.extend.refresh) Element.extend.refresh();
  Element.cache = { };
};

Element.Storage = {
  UID: 1
};

Element.addMethods({
  /**
   *  Element.getStorage(@element) -> Hash
   *
   *  Returns the [[Hash]] object that stores custom metadata for this element.
  **/
  getStorage: function(element) {
    if (!(element = $p(element))) return;

    var uid;
    if (element === window) {
      uid = 0;
    } else {
      if (typeof element._prototypeUID === "undefined")
        element._prototypeUID = Element.Storage.UID++;
      uid = element._prototypeUID;
    }

    if (!Element.Storage[uid])
      Element.Storage[uid] = $H();

    return Element.Storage[uid];
  },

  /**
   *  Element.store(@element, key, value) -> Element
   *
   *  Stores a key/value pair of custom metadata on the element.
   *
   *  The metadata can later be retrieved with [[Element.retrieve]].
  **/
  store: function(element, key, value) {
    if (!(element = $p(element))) return;

    if (arguments.length === 2) {
      // Assume we've been passed an object full of key/value pairs.
      Element.getStorage(element).update(key);
    } else {
      Element.getStorage(element).set(key, value);
    }

    return element;
  },

  /**
   *  Element.retrieve(@element, key[, defaultValue]) -> ?
   *
   *  Retrieves custom metadata set on `element` with [[Element.store]].
   *
   *  If the value is `undefined` and `defaultValue` is given, it will be
   *  stored on the element as its new value for that key, then returned.
  **/
  retrieve: function(element, key, defaultValue) {
    if (!(element = $p(element))) return;
    var hash = Element.getStorage(element), value = hash.get(key);

    if (Object.isUndefined(value)) {
      hash.set(key, defaultValue);
      value = defaultValue;
    }

    return value;
  },

  /**
   *  Element.clone(@element, deep) -> Element
   *  - deep (Boolean): Whether to clone `element`'s descendants as well.
   *
   *  Returns a duplicate of `element`.
   *
   *  A wrapper around DOM Level 2 `Node#cloneNode`, [[Element.clone]] cleans up
   *  any expando properties defined by Prototype.
  **/
  clone: function(element, deep) {
    if (!(element = $p(element))) return;
    var clone = element.cloneNode(deep);
    clone._prototypeUID = void 0;
    if (deep) {
      var descendants = Element.select(clone, '*'),
          i = descendants.length;
      while (i--) {
        descendants[i]._prototypeUID = void 0;
      }
    }
    return Element.extend(clone);
  },
  
  /**
   *  Element.purge(@element) -> null
   *  
   *  Removes all event listeners and storage keys from an element.
   *  
   *  To be used just before removing an element from the page.
  **/
  purge: function(element) {
    if (!(element = $p(element))) return;    
    var purgeElement = Element._purgeElement;
    
    purgeElement(element);

    var descendants = element.getElementsByTagName('*'),
     i = descendants.length;

    while (i--) purgeElement(descendants[i]);

    return null;
  }
});

Element.addMethods();
/**
 * document.stage
 *
 * Donne les informations sur la stage comme la hauteur et la largeur
 * de la scène, c'est-à-dire la partie visible de la page HTML.
 **/
document.stage = {
/**
 * document.stage.body -> Element
 * Cette attribut est une référence sur la balise body du document HTML.
 **/
	body: '',
/**
 * document.stage.stageHeight -> Number
 * Donne la hauteur du corps visible de la page HTML.
 **/
	stageHeight:0,
/**
 * document.stage.stageWidth -> Number
 * Donne la largeur du corps visible de la page HTML.
 **/
	stageWidth:0,
/**
 * document.stage.getDimensions() -> Object
 * 
 * Donne la dimensions de la scène Body.
 * 
 * ##### Composition de l'objet de retour 
 *	
 *     {
 *          0: {@link Number} largeur,
 *          1: {@link Number} hauteur,
 *          'height' : {@link Number} height,
 *          'width' : {@link Number} largeur
 *     }
 *
 **/
	getDimensions:function(){
		var div = new Node('div');
		
		div.setStyle({
					 height:	"1px",
					 width:		"100%",
					 position:	"fixed",
					 bottom:	"0",
					 left:		"0",
					 backgroundColor:'black'
					 });
		
		this.body.appendChild(div);
		
		this.stageWidth = 	Element.getWidth(div);
		this.stageHeight = 	Element.cumulativeOffset(div).top;
	
		this.body.removeChild(div);
		
		return {
			'0': this.stageWidth,
			'1': this.stageHeight, 
			height:this.stageHeight, 
			width:this.stageWidth
		};
	}
};


var $Body = null;

Extends.load();

$(document).ready(function(evt){
	try{
		
		$Body = document.stage.body = document.getElementsByTagName("body")[0];
		document.stage.getDimensions();
		
		$Body.getDimensions = 	document.stage.getDimensions.bind(document.stage);
		$Body.getStageHeight =	function(){return document.stage.stageHeight};
		$Body.getStageWidth =	function(){return document.stage.stageWidth};
		
		/*
		 * @ignore
		 */
		//window.onresize = function(evt){
			//document.stage.getDimensions(evt);
			//Extends.fire('resize', evt);
		//};
		Extends.fire('dom:loaded', evt);
		
	}catch(er){
		alert(er+ ' '+er.lineNumber)
	}
});